前言
自從此部落格發表以及程式碼開源以來,得到了許多人的關注。也沒許多吧,反正在我意料之外的。包括幾位大牛幫我做訂閱號推廣,真的很感謝他們。另外,還有幾個高手給我提了一些架構上的問題。其實本身這個專案是沒有做什麼架構設計的。只是簡單分了分層。不過我在經過仔細思考之後決定對專案架構做些調整,當然在我的技術範圍之內,我相信還會有第二次,第三次甚至更多重構,我希望把他變得更加完美。
重構思路
對於重構思路,我首先想到的是,讓程式能夠支援多種資料庫,比如我現在用的是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對接,為了模擬演示,資料為程式碼中寫死的。見上文)
總結
哦啦,雖然這個例子稍微有點簡單,但是也比之前的程式碼好了一點,程式碼重構的過程是很痛苦的,你要推翻你以前寫的好多程式碼,甚至整個專案都要重寫。路還長,這個專案也是讓我成長不少,繼續加油。沒有看過此係列的小夥伴可以移步這裡哦: