本章內容主要包括兩個方面,一、是框架分層(控制器、業務對象、實體、Dao)的詳細說明,二、是對比常用三層結構的區別和優勢;
本文要點:
1.框架中的各個分層詳細說明
2.對比常用三層結構的區別和優勢
3.分享兩個項目中的小經驗
4.網絡資料
我們先看一下前面實例中的解決方案目錄:
我們再看各層之間的調用關系:
上圖描敘的控制器有四種方式來操作數據庫,
1)控制器調用實體,通過框架中的ORM來實現單表的操作
2)控制器直接操作數據庫對象(oleDB),通過編寫SQL語句訪問數據庫
3)控制器通過調用Dao操作數據庫
4)控制器調用業務對象,業務對象再調用Dao操作數據庫
還有就是每一層在程序結構中承擔的角色;
一、Dao
數據訪問對象,新建一個Dao必須繼承繼承框架中的AbstractDao對象,AbstractDao對象中封裝了數據庫操作對象oleDb,所以Dao中的方法都是直接編寫SQL語句操作數據庫;
public class BookDao : EFWCoreLib.CoreFrame.BusinessArchitecture.AbstractDao { public DataTable GetBooks(string searchChar, int flag) { string strsql = @"SELECT * FROM dbo.Books WHERE BookName LIKE '%{0}%' AND Flag={1}"; strsql = string.Format(strsql, searchChar, flag); return oleDb.GetDataTable(strsql); } }
上面代碼是實現對Sqlserver數據庫的操作,如果要實現不同數據庫的操作,如:Oracle、DB2等,要如何實現?很簡單,先創建IBookDao接口,再分別實現SqlBookDao和OracleBookDao,控制器訪問Dao只需調用IBookDao接口就行了,而最后操作哪個數據庫的Dao在EFWUnity.config配置文件中配置好。
IBookDao接口
public interface IBookDao { System.Data.DataTable GetBooks(string searchChar, int flag); }
SqlBookDao對象
public class SqlBookDao : EFWCoreLib.CoreFrame.BusinessArchitecture.AbstractDao, Books.Dao.IBookDao { public DataTable GetBooks(string searchChar, int flag) { string strsql = @"SELECT * FROM dbo.Books WHERE BookName LIKE '%{0}%' AND Flag={1}"; strsql = string.Format(strsql, searchChar, flag); return oleDb.GetDataTable(strsql); } }
OracleBookDao對象
public class OracleBookDao : EFWCoreLib.CoreFrame.BusinessArchitecture.AbstractDao, Books.Dao.IBookDao { public DataTable GetBooks(string searchChar, int flag) { string strsql = @"SELECT * FROM Books WHERE BookName LIKE '%{0}%' AND Flag={1}"; strsql = string.Format(strsql, searchChar, flag); return oleDb.GetDataTable(strsql); } }
EFWUnity.config配置文件
控制器中通過NewDao<>操作方法,創建配置的SqlBookDao對象
綜合上述,不同數據庫Dao結構設計如下:
二、Entity實體
實體代碼都是用工具,根據數據庫表結構信息生成的;所有實體都必須繼承框架中的AbstractEntity對象,而實體與數據庫表之間的映射不需要另外xml配置文件,而是利用自定義標簽實現ORM映射;TableAttribute標簽映射實體類名與數據庫表,ColumnAttribute標簽映射實體屬性與數據庫表字段。一個實體映射到多個表也可以,直接類名上配置多個TableAttribute標簽和屬性上配置多個ColumnAttribute標簽,不過要用標簽的Alias參數區分。
三、ObjectModel業務對象
業務對象在書籍管理實例並沒有建此對象,因為業務太簡單了,只有當業務流程很復雜或范圍涉及廣的情況,就可以考慮建一些業務對象來解決這些問題;所有業務對象必須繼承框架中的AbstractBusines對象,業務對象中不能直接操作數據庫,必須通過Dao來訪問。另外就是如果多個業務對象是用來解決同一個問題,一般我們使用工廠模式來設計,在框架中可以使用EFWUnity.config配置文件進行業務對象映射;
四、Controller控制器,包括WebController、WinController、WcfController、WcfClientController
控制器分為3種模式,不同模式分別建控制器。控制器在程序結構中的作用就是承上啟下,比如WebController控制器,就是把調用邏輯層返回的數據結構轉換為統一Json字符串傳遞給界面JqueryEasyUI。而不同的界面框架則需要對框架中的Webcontroller進行擴展,以后我們會詳細講解各種控制器的實現;
還有就是Controller中提供了數據庫的操作對象OleDB,允許控制器直接編寫SQL語句操作數據庫,為什么要放開此功能,這也是在項目中遇到的實際情況而不得不妥協的一種設計;
同樣所有控制器也都必須框架中的基類控制器,基於JqueryEasyUI的Webcontroller繼承AbstractJqueryController對象,WinController繼承BaseController對象,wcfController繼承JsonWCFController對象;wcfClientController繼承BaseWCFClientController對象;
再就是控制器暴露給界面UI,還必須加上控制器的自定義標簽,WebController的WebController和WebMethod,WinController的Menu,wcfClientController的WCFController和WCFMethod;
通過上面的介紹,應該對EnterpriseFrameWork框架的分層結構有一定得了解,下面我們討論一下,與常用三層結構的區別與優勢?
軟件分層意義主要就包括解耦和復用,也許還能讓代碼維護與擴展更方便;三層結構分別包括界面層、邏輯層和數據層。EnterpriseFrameWork框架中的分層也可以說是三層,只是叫法與承擔的職責不一樣,並且EnterpriseFrameWork框架中的分層可以隨時變化的,不同情況有4種方式對分層進行調整,所以EnterpriseFrameWork框架分層的兼容性強。有哪些不同情況,可以總結為兩種,一是根據具體功能的難易程度,二是根據開發人員的代碼水平;
我們對比一下PetShop項目的程序結構:
PetShop項目名稱及描述:(實現步驟為:4-3-6-5-2-1)
1、WEB=表示層
2、BLL=業務邏輯層
3、IDAL=數據訪問層接口定義
4、Model=業務實體
5、DALFactory=數據層的抽象工廠(創建反射)
6、SQLServerDAL=SQLServer數據訪問層 / OracleDAL=Oracle數據訪問層 DBUtility 數據庫訪問組件基礎類
其中3中的IDAL對應EnterpriseFrameWork框架中的Dao接口,Model對應框架中的實體,SQLServerDAL和OracleDAL對應不同數據庫Dao;而不同的有5中的DALFactory在框架中是不需要的,只需配置文件中配置即可;2中的BLL也職責不一樣,框架中更趨向領域模型的設計;1中的WEB表示層,框架中單獨把Controller控制器分出來獨立一層;所以對比兩者發現其思想還是差別比較大的,個人覺得EnterpriseFrameWork框架除了在程序代碼的解耦,更在業務、項目等實際情況方面更加合適;
接着再討論一下:貧血模型與充血模型?
貧血模型:是指領域對象里只有get和set方法,或者包含少量的CRUD方法,所有的業務邏輯都不包含在內而是放在Business Logic層。
充血模型:層次結構和上面的差不多,不過大多業務邏輯和持久化放在Domain Object里面,Business Logic(業務邏輯層)只是簡單封裝部分業務邏輯以及控制事務、權限等。
對這兩種模型的使用個人感覺比較深刻,以前還不知道這種寫法是貧血模型,表生成所有實體,再就是調用實體的N個邏輯對象,這樣的代碼就越寫越過程化,基本上一個系統分成幾個邏輯對象就完成了,沒有了對象的概念;后來就覺得這樣不對,就把實體擴展成一個完整的業務對象,實現對這個實體的所有業務操作方法;這樣剛開始還蠻有感覺,但后來越做越別扭,一是很多實體根本沒有業務操作,還有就是一個業務操作會跨多個實體;在實體上來補充業務操作方法本來就不太合理,因為表結構的設計本來就不是基於面向對象的;所以后來就演變為現在EnterpriseFrameWork框架中ObjectModel這種模型,我叫做領域對象模型;簡單的業務走第一種模式,復雜的業務就必須分析出領域模型並設計業務對象;
最后分享兩個項目中的小經驗,一個是與大學高校合作開發項目、另一個是小公司老板的見解;
與大學高校合作開發一個不算太復雜的項目,公司方負責需求的收集與分析,高校針對需求進行設計與開發;高校由一個研究生導師帶隊,也沒用什么技術框架,就是常用的三層結構,合作的過程就不講了,反正就是最后到我接手維護代碼的時候就感覺到這個系統的坑人之處;首先不算復雜的系統項目建了十多個,找代碼文件很難找,再就是每改一個小地方要改多個文件從界面層改到數據層;最受不了的就是代碼的閱讀與調試相當麻煩,每層之間又通過一個工廠反射類名方法名調用;最后我們得出的結論就是在實際項目千萬不能交給高校開發,他們可以搞一些研究項目,做的時候又沒有考慮到一些實際情況;
小公司老板的見解。一朋友自己做老板創業,懂點php網頁開發,在學校招了幾個剛畢業生准備研發一個新產品,要我幫忙他們搭建系統框架,我推薦最早框架給他們使用,那時候在Controller中並沒有OleDB操作數據庫;我先把系統的核心業務開發完成,招的幾個畢業生就在此基礎上繼續完善系統,剛開始我在的時候還好,有什么不明白的我幫忙解決,后來我抽出來后,他們做着做着問題就暴露出來了,一個簡單的功能很久都搞不出來,新產品講究的就是速度嘛,馬上要給客戶看的;所以朋友急了開始找原因,雖然朋友就會個php網頁制作,但通過與幾個畢業生深入溝通,他發現程序分層太復雜了,做一個功能要畫界面,寫控制器、寫業務對象、寫Dao才能完成,更難的他們根本對邏輯層的控制器、業務對象、Dao理解不了,所以一定要他們這樣用就經常搞出一些莫名其妙的問題;朋友就說為什么不能直接在控制器中寫sql語句,這樣開發起來多簡單?我就說這樣放開不行,會破壞整個程序的分層結構,以后代碼的維護、擴展都會有問題,但我的這些以后說服不了他,他覺得這些以后版本可以優化,現在就是要馬上出來;最后只要在控制器也開放了Oledb操作數據庫;
網絡上對於三層結構的解釋:
數據訪問層:有時候也稱為是持久層,其功能主要是負責數據庫的訪問。簡單的說法就是實現對數據表的Select,Insert,Update,Delete的操作。如果要加入ORM的元素,那么就會包括對象和數據表之間的mapping,以及對象實體的持久化。在PetShop的數據訪問層中,並沒有使用ORM,從而導致了代碼量的增加,可以看作是整個設計實現中的一大敗筆。
業務邏輯層:是整個系統的核心,它與這個系統的業務(領域)有關。以PetShop為例,業務邏輯層的相關設計,均和網上寵物店特有的邏輯相關,例如查詢寵物,下訂單,添加寵物到購物車等等。如果涉及到數據庫的訪問,則調用數據訪問層。
表示層:是系統的UI部分,負責使用者與整個系統的交互。在這一層中,理想的狀態是不應包括系統的業務邏輯。表示層中的邏輯代碼,僅與界面元素有關。在PetShop中,是利用ASP.Net來設計的,因此包含了許多Web控件和相關邏輯。
分層的好處
1、開發人員可以只關注整個結構中的其中某一層;
2、可以很容易的用新的實現來替換原有層次的實現;
3、可以降低層與層之間的依賴;
4、有利於標准化;
5、利於各層邏輯的復用。
概括來說,分層式設計可以達至如下目的:分散關注、松散耦合、邏輯復用、標准定義。
分層的壞處:
1、降低了系統的性能。這是不言而喻的。如果不采用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。
2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼。