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

    前言

      自从此博客发表以及代码开源以来,得到了许多人的关注。也没许多吧,反正在我意料之外的。包括几位大牛帮我做订阅号推广,真的很感谢他们。另外,还有几个高手给我提了一些架构上的问题。其实本身这个项目是没有做什么架构设计的。只是简单分了分层。不过我在经过仔细思考之后决定对项目架构做些调整,当然在我的技术范围之内,我相信还会有第二次,第三次甚至更多重构,我希望把他变得更加完美。

    重构思路

      对于重构思路,我首先想到的是,让程序能够支持多种数据库,比如我现在用的是SQLServer,而好多朋友用MySQL或者mongodb等其他数据库,本来初衷没有想这么多,认为此项目就是一个关于SignalR和LayIM的Demo实现。不过能优化一下是最好的。然后我就想到了一个经典的用法,那就是反射工厂。通过反射来动态生成对象,然后调用方法,而不用去改UI的代码。

      比如,当我同样写了一个MySQL的获取用户基础信息的方法,那么我就需要去改Controller中的代码:

      

         public JsonResult GetBaseList(int userid)
            {
                //SQLServer数据库调用方法
                //var result = LayimUserBLL.Instance.GetChatRoomBaseInfo(userid);
                //MySQL数据库调用方法
                //var result = LayimUserBLL_MySQL.Instance.GetChatRoomBaseInfo(userid);
                return Json(result, JsonRequestBehavior.AllowGet);
            }

      这样的话要改动的地方太多了,其实重构也很花费时间,但是是值得的。于是我先在BLL层定义了方法接口。

      public interface IUser : ISearch
        {
    
            #region 获取用户登录聊天室后的基本信息
            JsonResultModel GetChatRoomBaseInfo(int userid);
            #endregion
    
            #region 获取群组人员信息
            JsonResultModel GetGroupMembers(int groupid);
            #endregion
    
            #region 用户登录或者注册流程
            /// <summary>
            /// 用户登陆或者注册,返回用户id如果为 0 说明密码错误
            /// </summary>
            /// <param name="loginName"></param>
            /// <param name="loginPwd"></param>
            /// <param name="nickName"></param>
            /// <returns></returns>
            int UserLoginOrRegister(string loginName, string loginPwd);
    
            #endregion
    
            #region 用户创建群
            JsonResultModel CreateGroup(string groupName, string groupDesc, int userid);
            #endregion
    
            #region 获取用户有关的消息
            JsonResultModel GetUserApplyMessage(int userid);
            #endregion
    
            #region 获取某个用户的好友列表
            /// <summary>
            /// 获取某个用户的好友列表
            /// </summary>
            /// <param name="userid">用户ID</param>
            /// <returns>返回格式如下 ""或者 "10001,10002,10003"</returns>
            string GetUserFriends(int userid);
            #endregion
    
            #region 读取用户所在的群
            string[] GetUserAllGroups(string userId);
            #endregion
    
    
        }

      这样,我在把原本LayimBLL继承这个接口,然后相应的改一下代码。基本不用变,因为我定义这个接口的时候就是参照原类中的方法定义的。同样,在MySQL文件夹下同样新建一个类继承自这个接口,然后模拟一个MySQL的实现。

        public JsonResultModel GetChatRoomBaseInfo(int userid)
            {
                var result = new BaseListResult();
                result.mine = new UserEntity
                {
                    avatar = "/headphotos/default.jpg",
                    id = 1,
                    sign = "我来自MySQL",
                    status = "online",
                    username = "MySQL"
                };
                return JsonResultHelper.CreateJson(result, true);
            }

      那么反射工厂做了什么工作呢。通过读取配置文件来动态生成相应的对象实例。核心代码就在于Type.GetType方法,然后调用Activator.CreateInstance方法创建实例。

      public class LayIMFactory
        {
            #region 私有变量和方法
            readonly string asemmblyPath = "LayIM.BLL.Classes.{0}.{1},LayIM.BLL";
            private string InstanceName
            {
                get { return AppSettings.GetValue("DBType"); }
            }
            private string GetFullAsemmblyPath(string className)
            {
                return string.Format(asemmblyPath, InstanceName, className);
            }
            #endregion
    
            public IUser Create()
            {
                return Create<IUser>(BLLClasses.User);
            }
    
            /// <summary>
            /// 通过反射来获取某个类的实例
            /// </summary>
            /// <typeparam name="IT"></typeparam>
            /// <param name="className"></param>
            /// <returns></returns>
            private IT Create<IT>(string className)
            {
                var nameSpace = GetFullAsemmblyPath(className);
                Type t = Type.GetType(nameSpace);
                IT instance = (IT)Activator.CreateInstance(t);
                return instance;
            }
        }

      然后,Controller稍微改动一下。这样Controller只希望要一个实现IUser接口的实例对象,并不关系你内部用的是MySQL还是SQLServer,这样能够实现Controller和BLL层解耦的目的。

      

        当然后边我做的工作很多,代码就不全粘了。下面运行一下,看看效果。

    重构后的代码演示

      首先配置文件中的,DBType我们把值设为SQLServer.(图片中的数据是从sqlserver数据库中读取的)

      

      然后再将配置文件中的DBType的值改为MySQL(由于尚未开发和MySQL对接,为了模拟演示,数据为代码中写死的。见上文)

         

    总结

      哦啦,虽然这个例子稍微有点简单,但是也比之前的代码好了一点,代码重构的过程是很痛苦的,你要推翻你以前写的好多代码,甚至整个项目都要重写。路还长,这个项目也是让我成长不少,继续加油。没有看过此系列的小伙伴可以移步这里哦:

      ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列(不断更新中)

  • 相关阅读:
    新博客即将启用
    关于博主 | 联系博主
    结束吧,为这不圆满的故事划上一个残缺的句号
    自用线段树模板
    NOIP 2017 day 1 游记
    NOIP 2017 Day 0. 游记
    NOIP 2017 day -1 杂记
    再一次想不出应该起什么标题
    做图与树做到吐的一天
    自用二分图匹配模板
  • 原文地址:https://www.cnblogs.com/panzi/p/5840912.html
Copyright © 2011-2022 走看看