最近一直致力於Winform開發框架的重構工作,因為發現要維護傳統Winform開發框架、WCF開發框架、混合式開發框架,以及相關的模塊,包括權限管理、字典管理模塊、附件管理、人員管理等一些輔助模塊,很多代碼都會有重復的部分,優化的框架是想提高效率,減少冗余重復代碼,本文總結Winform開發框架重構工作中的一些經驗總結,以饗讀者,希望能夠對大家有一定的參考作用。
1、公用類庫的分離處理
我的公用類庫是自己開發這么多年的總結、收集和整理,對大多數的類庫均進行優化整理過,公用類庫的本意是對.NET內置的類庫進行包裝使用,提高使用效率和減少復雜性,隨着開發項目的增多和不斷的總結,有時候一些常用的第三方類庫包裝類也很常見,使用很頻繁,經常在各個模塊中使用,因此把框架中常用到的類庫分為兩類,一個是".NET內置類公用類庫“,一個是第三方類庫的包裝類,如我經常用到的Aspose.Cell、Apose.Word、NPOI、Myxls等Office相關類庫的包裝類,還有Log4Net日志類、Zip壓縮類庫等等,如下界面是一個截圖。
這樣雖然在管理上增加多了一個公用類庫的程序集,但是這樣區分有利於我們對類庫的擴展和維護。
2、Winform框架基類的封裝和獨立
在這次的重構工作中,很大程度上是提取所有框架和模塊中用到的各種基類到一個第三方類庫包裝類里面,然后在框架里面統一使用這個類庫,如原來數據訪問里面常用到的BaseBLL、BaseDAL、IBaseDAL、AbstractBaseDAL,其中BaseDAL雖然繼承了AbstractBaseDAL絕大多數的方法,但是不同的數據庫還是有一些小差異的,因此把BaseDAL分為了幾個不同數據庫版本的BaseDAL,包括Access、MySql、Oracle、SqlServer、Sqlite等數據庫的基類。
這樣把它們獨立出來,不用再每個數據訪問的模塊都復制一份,而且可以方便統一維護和升級,因為基類和接口一旦增加,所有的業務類都會同時具有增加的功能,非常利於維護擴展。除了數據訪問相關的基類,還對WCF服務等相關的基類也進行了抽取,這樣在WCF框架或者混合型框架中,就可以直接使用了。
3、在框架中使用封裝獨立的基類
1)傳統Winform框架的對象
把這些框架中常用到的類庫獨立抽取出來后,整個框架文件就比較簡潔很多了,也不用再多個模塊經常使用BeyondCompare比較來比較去的,框架業務層和數據訪問層的項目截圖如下所示,業務層除了有一個BLLFactory類外,其他的類都是常規的業務處理對象,BLLFactory沒有提取到公用類庫,是因為需要當前執行類的一些信息來構造業務對象和數據訪問對象;SqlServer數據訪問層則沒有任何多余的輔助類庫。
其中SqlServer數據訪問層的類,類定義的部分代碼如下所示。
using WHC.Pager.Entity; using WHC.WareHouseMis.Entity; using WHC.WareHouseMis.IDAL; using WHC.Framework.Commons; using WHC.Framework.ControlUtil; using Microsoft.Practices.EnterpriseLibrary.Data; namespace WHC.WareHouseMis.DALSQL { /// <summary> /// 備件信息數據訪問類 /// </summary> public class ItemDetail : BaseDALSQL<ItemDetailInfo>, IItemDetail { ......................
2)混合型框架的對象
在混合型框架對於WCF或者傳統Winfrom數據訪問中,我在其中定義了一個通用的接口層---Facade層,然后分兩種實現方式,其中Facade層的接口項目文件如下所示,其中可以看到,除了CallerFactory類外,其他部分均為接口定義,基類接口已經抽取到獨立的類庫里面去了。
混合型框架的調用示例代碼如下所示,其中和傳統的Winform調用BLLFactory一樣,這里只需要調用CallerFactory構造類即可,而傳入給CallerFactory的是Facade層的接口,工廠會根據配置參數進行相應的對象構造,從而實現基於傳統本地的數據庫訪問或者分布式的WCF數據訪問方式的綜合處理。
bool exist = CallerFactory<IItemDetailService>.Instance.CheckExist(this.txtItemNo.Text, ID); if (exist) { MessageDxUtil.ShowTips("指定的備件編號已經存在,不能重復添加,請修改"); return false; } ItemDetailInfo info = CallerFactory<IItemDetailService>.Instance.FindByID(ID); if (info != null) { .....................................
其中Facade層的CallerFactory對象,會根據配置信息,尋找並構建相應的實現類,有可能是傳統的數據訪問類,也可能是WCF的數據訪問類,這兩種實現類的定義如下所示。
using WHC.WareHouseMis.Entity; using WHC.WareHouseMis.BLL; using WHC.WareHouseMis.Facade; using WHC.Framework.ControlUtil; using WHC.Framework.ControlUtil.Facade; namespace WHC.WareHouseMis.WinformCaller { public class ItemDetailCaller : BaseLocalService<ItemDetailInfo>, IItemDetailService { private ItemDetail bll = null; public ItemDetailCaller() : base(BLLFactory<ItemDetail>.Instance) { bll = baseBLL as ItemDetail; } #region IItemDetailService 成員 public List<ItemDetailInfo> FindByBigType(string bigType) { return bll.FindByBigType(bigType); } ........................
而對於WCF方式的實現類方式如下所示
using WHC.WareHouseMis.Entity; using WHC.WareHouseMis.Facade; using WHC.Framework.Commons; using WHC.Framework.ControlUtil.Facade; namespace WHC.WareHouseMis.ServiceCaller { public class ItemDetailCaller : BaseWCFService<ItemDetailInfo>, IItemDetailService { public ItemDetailCaller() : base() { this.configurationPath = EndPointConfig.WcfConfig; this.endpointConfigurationName = EndPointConfig.ItemDetailService; }public List<ItemDetailInfo> FindByBigType(string bigType) { List<ItemDetailInfo> result = new List<ItemDetailInfo>(); IItemDetailService service = CreateSubClient(); ICommunicationObject comm = service as ICommunicationObject; comm.Using(client => { result = service.FindByBigType(bigType); }); return result; } ..............
4 、使用引用文件方式代替復制文件方式
在一個框架里面,為了減少程序集的數量和多個引用,可能會有多處需要使用同一個文件,這樣就可以使用文件引用的方式,在VS里面添加現有文件的時候,選擇
如由於我的某一個框架里面,為了減少程序集的數量,我把很多相關的類庫集成在一起,形成一個單一的程序集就具有很多功能,但這樣的代碼雖然有很多個影子,但是肉身只有一個,方便維護。
這樣對於某個文件的多處使用,但是統一維護很方便。
5、代碼生成工具Database2Sharp的支持
以上的一些對象繼承關系和框架的整體代碼,項目工程之間程序集的引用,這些手工操作的話,肯定效率大打折扣,因此代碼生成工具的支持是非常必要的工作,本框架系列的最新繼承關系,全部能夠使用Database2Sharp的完美支持,從而使得我們在日常開發過程中,享受快速、高效、統一的代碼生成帶來的樂趣。
以上就是我在框架重構中的一些總結,希望能給大家有所啟發,有所幫助。最后附上Winform開發框架的一個功能總結圖形,Winform開發框架的主要功能概覽如下圖所示。