上一篇中,咱們用了反射工廠來解除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的同窗趕忙試試用這個方法切換緩存吧。不知道我在說些什麼的同窗能夠移步這裏哦: