自今後博客發表以及代碼開源以來,獲得了許多人的關注。也沒許多吧,反正在我意料以外的。包括幾位大牛幫我作訂閱號推廣,真的很感謝他們。另外,還有幾個高手給我提了一些架構上的問題。其實自己這個項目是沒有作什麼架構設計的。只是簡單分了分層。不過我在通過仔細思考以後決定對項目架構作些調整,固然在個人技術範圍以內,我相信還會有第二次,第三次甚至更多重構,我但願把他變得更加完美。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對接,爲了模擬演示,數據爲代碼中寫死的。見上文)設計
哦啦,雖然這個例子稍微有點簡單,可是也比以前的代碼好了一點,代碼重構的過程是很痛苦的,你要推翻你之前寫的好多代碼,甚至整個項目都要重寫。路還長,這個項目也是讓我成長很多,繼續加油。沒有看過此係列的小夥伴能夠移步這裏哦: