自今后博客发表以及代码开源以来,获得了许多人的关注。也没许多吧,反正在我意料以外的。包括几位大牛帮我作订阅号推广,真的很感谢他们。另外,还有几个高手给我提了一些架构上的问题。其实自己这个项目是没有作什么架构设计的。只是简单分了分层。不过我在通过仔细思考以后决定对项目架构作些调整,固然在个人技术范围以内,我相信还会有第二次,第三次甚至更多重构,我但愿把他变得更加完美。html
对于重构思路,我首先想到的是,让程序可以支持多种数据库,好比我如今用的是SQLServer,而好多朋友用MySQL或者mongodb等其余数据库,原本初衷没有想这么多,认为此项目就是一个关于SignalR和LayIM的Demo实现。不过能优化一下是最好的。而后我就想到了一个经典的用法,那就是反射工厂。经过反射来动态生成对象,而后调用方法,而不用去改UI的代码。sql
好比,当我一样写了一个MySQL的获取用户基础信息的方法,那么我就须要去改Controller中的代码:mongodb
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方法建立实例。sqlserver
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层解耦的目的。优化
固然后边我作的工做不少,代码就不全粘了。下面运行一下,看看效果。spa
首先配置文件中的,DBType咱们把值设为SQLServer.(图片中的数据是从sqlserver数据库中读取的)架构设计
而后再将配置文件中的DBType的值改成MySQL(因为还没有开发和MySQL对接,为了模拟演示,数据为代码中写死的。见上文)设计
哦啦,虽然这个例子稍微有点简单,可是也比以前的代码好了一点,代码重构的过程是很痛苦的,你要推翻你之前写的好多代码,甚至整个项目都要重写。路还长,这个项目也是让我成长很多,继续加油。没有看过此系列的小伙伴能够移步这里哦: