在這個紛繁的社會裡面,統一性的特點能夠帶來很多高效的產出、牢固的記憶,這種特征無論對於企 業、個人的開發工作,知識的傳承都有著非常重要的作用,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