ASP.NET SignalR 與 LayIM2.0 配合輕鬆實現Web聊天室(十二) 代碼重構使用反射工廠解耦(一)緩存切換

前言

  上一篇中,咱們用了反射工廠來解除BLL和UI層耦合的問題。固然那是最簡單的解決方法,再複雜一點的程序可能思路相同,可是在編程細節中須要考慮的就更多了,好比今天我在重構過程當中遇到的問題。也是接下來我要解決的問題,緩存模塊。爲何要解決這個問題呢,因爲咱們有些下載代碼運行的小夥伴,發現怎麼運行報錯,原來是沒有裝redis。但是我只想看layim和signalr代碼而已啊,不想裝什麼redis。那麼基於昨天的經驗,我把緩存模塊一樣提取出接口,而後加了一個原始的cache層。這個cache是基於System.Web.Caching.Cache來實現的。html

實現思路

  正如前言中所說,實現思路仍是利用反射工廠,讀取用戶的配置來反射動態生成對象。Cache代碼結構調整以下:web

  

  首先說明一下,因爲接口內部方法目前只是根據項目須要來設計,可能不全面或者不夠靈活,不過不要緊,後期能夠完善。目前接口(ICache)中包含以下方法:redis

 public interface ICache
    {
  
        /// <summary>
        /// 獲取緩存,根據key
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns>返回獲取到的值</returns>
        T Get<T>(string key);
        /// <summary>
        /// 增長緩存
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <returns>添加成功返回true,不然返回false</returns>
        bool Set<T>(string key, T value);
        bool Set<T>(string key, T value, DateTimeOffset offset);
        /// <summary>
        /// 判斷key是否存在
        /// </summary>
        /// <param name="key">key</param>
        /// <returns>存在返回true,不然返回false</returns>
        bool Exists(string key);
        /// <summary>
        /// 刪除緩存
        /// </summary>
        /// <param name="key"></param>
        /// <returns>返回是否刪除成功,true或者false</returns>
        bool Delete(string key);
   
        /// <summary>
        /// 獲取哈希表中的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashKey"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        T HashGet<T>(string hashKey, string key);
        /// <summary>
        /// 設置哈希緩存值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hashKey">hashKey</param>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <returns>返回是否設置成功</returns>
        bool HashSet<T>(string hashKey, string key, T value);
        /// <summary>
        /// 刪除哈希緩存中的某個key
        /// </summary>
        /// <param name="hashKey"></param>
        /// <param name="key"></param>
        /// <returns>返回是否刪除成功</returns>
        bool HashDelete(string hashKey, string key);

    }

  很簡單的幾個方法,相信複雜的項目或者需求確定要有更多的功能。這裏姑且不討論。而後咱們按照上圖中新建文件夾,分別對應咱們要切換的Cache類型。好比,我新建了,Memcached,Redis,Memory三個文件夾,前兩個不用說,第三個就是咱們使用框架自帶的Cache。下面的代碼是我參照網絡上的一段文章又簡單包裝了一下寫的。這裏寫這個Cache只是爲了後續提到的,咱們可以自由切換而已。能用第三方的緩存仍是用第三方的。代碼以下:(實現接口中的方法)編程

  

    public class Cache : ICache
    {

        private static System.Web.Caching.Cache _cache;
        const int defaultTime = 24 * 60;//一天
        public Cache() {
            //初始化
            _cache = HostingEnvironment.Cache;
            SaveTime = defaultTime;
        }
        public static double SaveTime
        {
            get;
            set;
        }
        public bool Delete(string key)
        {
            var obj =_cache.Remove(key);
            return obj != null;
        }

        public bool Exists(string key)
        {
            return true;
        }

        public T Get<T>(string key)
        {
            if (string.IsNullOrEmpty(key)) {
                return default(T);
            }
            return (T)_cache.Get(key);
        }

        public bool HashDelete(string hashKey, string key)
        {
            Hashtable table = Get<Hashtable>(hashKey);
            if (table == null) { return true; } else {
                if (table.ContainsKey(key)) {
                    table.Remove(key);
                }
            }
            return true;
        }

        public T HashGet<T>(string hashKey, string key)
        {
            Hashtable table = Get<Hashtable>(hashKey);
            if (table != null)
            {
                var value = table[key];
                if (value == null) {
                    return default(T);
                }
                return (T)value;
            }
            return default(T);
        }

        public bool HashSet<T>(string hashKey, string key, T value)
        {
            //這裏就是用hashtable作哈希保存
            Hashtable table = Get<Hashtable>(hashKey);
            if (table == null)
            {
                table = new Hashtable();
                table.Add(key, value);
            }
            else
            {
                if (table.ContainsKey(key))
                {
                    table[key] = value;
                }
                else
                {
                    table.Add(key, value);
                }
            }
            return Set(hashKey, table);
        }

        #region
        private void Insert(string key, object value, CacheDependency dependency, CacheItemPriority priority, CacheItemRemovedCallback callback)
        {
            _cache.Insert(key, value, dependency,System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(SaveTime), priority, callback);
        }

        private void Insert(string key, object value, CacheDependency dependency, CacheItemRemovedCallback callback)
        {
            Insert(key, value, dependency, CacheItemPriority.Default, callback);
        }

        private  void Insert(string key, object value, CacheDependency dependency)
        {
            Insert(key, value, dependency, CacheItemPriority.Default, null);
        }

        private  void Insert(string key, object value)
        {
            Insert(key, value, null, CacheItemPriority.Default, null);
        }
        #endregion
        public bool Set<T>(string key, T value)
        {
            Insert(key, value);
            return true;
        }

        public bool Set<T>(string key, T value, DateTimeOffset offset)
        {
            SaveTime = offset.Offset.Minutes;
            Insert(key, value);
            SaveTime = defaultTime;
            return true;
        }

    }

  這樣的話,咱們一樣用上一篇文章中寫的方法來生成對用的ICache對象。設計模式

  

   public class LayIMCacheFactory : LayIMFactory
    {
        public LayIMCacheFactory() {
            asemmblyPath = "LayIM.Cache.Classes.{0}.{1},LayIM.Cache";
            _type = "CacheType";
        }

        public ICache CreateCache()
        {
            return Create<ICache>(FactoryClasses.Cache);
        }

        public LayIMCache CreateLayIMCache()
        {
            ICache cache = CreateCache();
       
return new LayIMCache(cache); } }

  能夠看到,上述代碼中,CreateLayIMCache方法中返回的是LayIMCache,是由於LayIMCache至關於業務層了,雖然也作了接口,可是(暫時)沒有必要再區分了,由於,在構造函數中,我把ICache的實例傳給LayIMCache中,而後內部調用相應的Cache方法,而後再最外部調用LayIMCache。可能把你們繞暈了。畫個圖更形象一些.(我也不會UML圖,實在慚愧,將就看吧~)緩存

  如今咱們來演示一下。怎麼能看出不一樣呢,因爲Redis使可以將咱們存的緩存數據持久化的。而Memory的這個Cache只要程序停了,他就消失了。那麼,咱們能夠經過驗證登陸token的方法來測試。首先Redis沒必要說。咱們更改web.config中的CacheType值。網絡

<!--緩存類型,Redis Memory,Memcached-->
<add key="CacheType" value="Memory" />

  這裏要注意,不管是Memory仍是Redis或者其餘,這裏的配置字母必定要寫正確,不然反射生成實例的時候會報錯。框架

  咱們運行一下,打斷點調試:函數

  

  這時候咱們在關閉程序,從新運行調試,咱們走到token驗證,看一下內容,已經沒有了,以下圖,驗證已經進入非受權條件內。測試

  

總結

  本篇已經接近尾聲了,原來寫代碼寫多了,頭腦真的會升華。之前看設計模式中的代碼壓根體會不到其中的奧妙,現在專門作一下代碼重構工做才能真正體驗到代碼設計的精妙之處。騷年還須要努力啊。今天的代碼重構工做就到此結束,不想裝Redis的同窗趕忙試試用這個方法切換緩存吧。不知道我在說些什麼的同窗能夠移步這裏哦:

ASP.NET SignalR 與 LayIM2.0 配合輕鬆實現Web聊天室 實戰系列(不斷更新中)

相關文章
相關標籤/搜索