zoukankan      html  css  js  c++  java
  • ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言

      上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题。当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题。也是接下来我要解决的问题,缓存模块。为什么要解决这个问题呢,由于我们有些下载代码运行的小伙伴,发现怎么运行报错,原来是没有装redis。可是我只想看layim和signalr代码而已啊,不想装什么redis。那么基于昨天的经验,我把缓存模块同样提取出接口,然后加了一个原始的cache层。这个cache是基于System.Web.Caching.Cache来实现的。

    实现思路

      正如前言中所说,实现思路还是利用反射工厂,读取用户的配置来反射动态生成对象。Cache代码结构调整如下:

      

      首先说明一下,由于接口内部方法目前只是根据项目需要来设计,可能不全面或者不够灵活,不过没关系,后期可以完善。目前接口(ICache)中包含如下方法:

     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聊天室 实战系列(不断更新中)

  • 相关阅读:
    openCR-用ROS代码获取电压的方法
    openCR-用ROS代码控制按键的方法
    TurtleBot3-基础例程
    TurtleBot3-键盘远程控制
    TurtleBot3-Topic Monitor
    openCR-串口打印HelloWorld
    Ubuntu播放音乐 mp3 wav
    SQL Server2008创建约束图解 转
    height、clientHeight、scrollHeight、offsetHeight区别
    第一次弄项目有感
  • 原文地址:https://www.cnblogs.com/panzi/p/5843536.html
Copyright © 2011-2022 走看看