在這個紛繁的社會裡面,統一性的特點能夠帶來很多高效的產出、牢固的記憶,這種特征無論對於企 業、個人的開發工作,知識的傳承都有著非常重要的作用,Winfrom框架本身就是基於這個理念而生,從 統一的數據庫設計規則開始,統一的項目格局,統一的業務類、數據訪問類、實體類繼承關系,再到統 一的公用類庫,統一的權限管理模塊,統一的字典管理模塊,統一的附件管理...,理解這些理念和規則 後,再來個終極的統一,框架代碼快速生成--Database2Sharp代碼生成工具。所有的框架(包括傳統 Winform開發框架、WCF開發框架、混合式開發框架、Web開發框架)都融合到這裡來,統一整合各種看似 零散,實則高度滲透的模塊,統一的步伐除了時間、效力外,帶來給我更多的饋贈。本文主要介紹我的 Winform框架(也包括其他框架的特點)的業務對象統一調用的方式,介紹如何通過BLLFactory或者 CallerFactory的公用類庫來實現各種業務對象的創建工作。
1、BLLFactory的對象統一調用規則
在我的框架裡面,所有的業務類調用都是以BLLFactory入口進行開始創建,傳遞業務對象進去即可創 建,這種統一入口的方式能夠方便記憶,並減少代碼,更重要的是能夠很好把一些如緩存規則、創建規 則封裝起來,簡化代碼。BLLFactory的創建示意圖如下所示。
既然是統一調用規則方式,那麼BLLFactory的類庫就應該提升到公用類庫的級別,所以提供Winform 框架支持的公用類庫如下所示。
當然,為了減少代碼,提高開發效率,整體的框架處處體現了代碼重用的規則,盡可能把重復的代碼 提取出來,因此還有很多如數據訪問基類、業務訪問基類、數據訪問基類接口、實體基類等類庫,結合 泛型能夠使我們的API更加統一化、強類型化,提高開發效率。由於BLLFactory是公用類庫級別,所有獨 立開發的模塊,也都是以該類庫為統一入口,創建所必須的對象。
我們看看框架如何能夠在紛繁復雜的類庫裡面,准確創建一系列的對象的。
BLLFactory業務對象工廠輔助類的代碼如下所示。
/// <summary> /// 對業務類進行構造的工廠類 /// </summary> /// <typeparam name="T">業務對象類型</typeparam> public class BLLFactory<T> where T : class { private static Hashtable objCache = new Hashtable(); private static object syncRoot = new Object(); /// <summary> /// 創建或者從緩存中獲取對應業務類的實例 /// </summary> public static T Instance { get { string CacheKey = typeof(T).FullName; T bll = (T)objCache[CacheKey]; //從緩存讀取 if (bll == null) { lock (syncRoot) { if (bll == null) { bll = Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射創建,並緩存 objCache.Add(typeof(T).FullName, bll); } } } return bll; } } }
其中利用了哈希表對象對創建的對象進行緩存,並進一步傳遞參數給Reflect公用類庫,對指定對象 全名、程序集的業務對象進行創建。
以上只是很薄的一層關系,一般我們都能夠很容易理解,但是我們知道,每個業務對象類,還需要負 責創建裡面的數據訪問基類(如IUser接口的數據訪問基類userDal),我們來繼續分析BaseBLL對象的工 作邏輯,才能很好理解其中的關系。
/// <summary> /// 用戶信息業務管理類 /// </summary> public class User : BaseBLL<UserInfo> { private IUser userDal; public User() : base() { base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); this.userDal = (IUser)base.baseDal; } .............................. }
其中Init的函數接口定義如下,主要就是根據相關參數,構建數據不同的數據訪問對象,如 SqlServer的訪問對象,或者Oracle的數據訪問對象等。
/// <summary> /// 參數賦值後,初始化相關對象 /// </summary> /// <param name="bllFullName">BLL業務類的全名(子類必須實現),子類構造函數傳入this.GetType().FullName</param> /// <param name="dalAssemblyName">數據訪問層程序集的清單文件的文件名,不包括其擴展名,可使用Assembly.GetExecutingAssembly().GetName().Name</param> /// <param name="bllPrefix">BLL命名空間的前綴(BLL.)</param> void Init(string bllFullName, string dalAssemblyName, string bllPrefix = "BLL.")
由於數據訪問也是基於反射方式(帶緩存)創建,因此需要知道數據訪問類的全名和對應的程序集, 如果整合在一個項目工程裡面,如我的框架結構代碼所示,那麼dalAssemblyName就是 System.Reflection.Assembly.GetExecutingAssembly().GetName().Name了。其中Init函數主要就是根 據配置的數據庫類型,創建指定類型的數據訪問業務對象,主要的邏輯代碼如下所示。
#region 根據不同的數據庫類型,構造相應的DAL層 AppConfig config = new AppConfig(); string dbType = config.AppConfigGet("ComponentDbType"); if (string.IsNullOrEmpty(dbType)) { dbType = "sqlserver"; } dbType = dbType.ToLower(); string DALPrefix = ""; if (dbType == "sqlserver") { DALPrefix = "DALSQL."; } else if (dbType == "access") { DALPrefix = "DALAccess."; } else if (dbType == "oracle") { DALPrefix = "DALOracle."; } else if (dbType == "sqlite") { DALPrefix = "DALSQLite."; } else if (dbType == "mysql") { DALPrefix = "DALMySql."; } #endregion this.dalName = bllFullName.Replace(bllPrefix, DALPrefix);//替換中級的BLL.為DAL.,就是DAL類的全名 baseDal = Reflect<IBaseDAL<T>>.Create(this.dalName, dalAssemblyName);//構造對應的DAL數據訪問層的對象類
由於BLLFactory<T>通過傳入指定的業務對象,成功創建後,會返回相關聯的類的實例,因此 接口的調用在設計時就知道了,也就是上面例子裡面的BLLFactory<BLL.User>.Instance就是 BLL.User類的實例,具有所有該類的接口方法,實現了強類型API的目的了。
下面就是該類在實際界面項目裡面的使用例子代碼。
try { UserInfo info = BLLFactory<User>.FindByID(currentID) as UserInfo; if (info != null) { info = SetUserInfo(info); BLLFactory<User>.Instance.Update(info, info.ID.ToString()); RefreshTreeView(); MessageDxUtil.ShowTips("資料保存成功"); } } catch (Exception ex) { LogTextHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); }
2、CallerFactory的對象統一調用規則
CallerFactory對象是用於創建基於Facade層接口的業務對象,主要用在我的WCF開發框架、混合式開 發框架裡面,該對象的創建邏輯類似於BLLFactory,不過它創建的對象,可能是基於WCF客戶代理的對象 ,也可能是對BLLFactory創建對象的進一步封裝,以便實現宏觀上的統一。如下圖所示,CallerFactory 處在下面框架結構圖的中間部分,UI層的下面。
CallerFactory的調用代碼例子如下所示。
{ UserInfo info = CallerFactory<IUserService>.Instance.FindByID(currentID); if (info != null) { info = SetUserInfo(info); CallerFactory<IUserService>.Instance.Update(info, info.ID.ToString()); RefreshTreeView(); MessageDxUtil.ShowTips("資料保存成功"); } } catch (Exception ex) { LogHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); }
查看本欄目
我們看到,雖然上面的代碼是基於WCF的分布式應用,我們還是可以看到,這個調用的思路和方式, 和傳統Winform的BLLFactory如出一轍,能解決對象調用問題的同時,這樣的操作方式,能夠給我們學習 框架提供了更好的統一模式,順利切換,而且,從傳統Winfrom開發框架的界面代碼遷移到分布式應用的 WCF開發上,界面代碼的變化也是很有規律的,這就是統一模式的力量和奧妙所在。
和BLLFactory裡面傳入的業務層對象不同,這裡CallerFactory裡面傳入的對象是Facade層的接口, 那麼它是如何知道我們要創建的對象,並把它轉換為我們需要的接口的呢?
/// <summary> /// 混合式框架或WCF框架中針對不同調用方式的工廠類(WCF或者Win調用) /// </summary> /// <typeparam name="T">接口類型</typeparam> public class CallerFactory<T> { private static Hashtable objCache = new Hashtable(); private static object syncRoot = new Object(); private static string callerNamespace = null;//Facade接口實現類的命名空間 /// <summary> /// 創建或者從緩存中獲取對應接口的實例 /// </summary> public static T Instance { get { string CacheKey = typeof(T).FullName; T bll = (T)objCache[CacheKey]; //從緩存讀取 if (bll == null) { lock (syncRoot) { if (bll == null) { bll = CreateObject(); //反射創建,並緩存 if (bll != null) { objCache.Add(typeof(T).FullName, bll); //緩存BLL業務對象 } } } } return bll; } }
從上面的代碼我們看到,這裡的創建邏輯和BLLFactory很大程度的相同,只是細節部分,我使用了 CreateObject 進行了隔離,放到獨立的函數裡面進行創建了。
CreateObject 函數主要邏輯就是根據WCF框架配置信息,到具體的程序集裡面創建對應的對象實例, 然後轉換為Facade層接口,方便統一調用。這就是我WCF開發框架和混合式開發框架,統一調用接口進行 通訊獲取或提交數據的工作模式。
以上就是我Winform開發框架、WCF開發框架、混合式開發框架、Web開發框架裡面所用到的兩種方式 的對象創建方式的說明,希望您能從統一的調用方式可以看到更多的奧妙及好處。
關於以上幾種框架的定義說明,請查看下面圖示的介紹,打開圖示可以查看更多的框架介紹內容。
伍華聰 http://www.iqidi.com