剛剛看到園子里有人問這個問題,心血來潮,整理一番,希望對初學oop的有所幫助,同時有理解不對的歡迎指正。
假設我們做一個簡單的小系統,需要的操作為:
1.管理用戶,對用戶進行增、刪、改(User表)
2.管理角色,對角色進行增、刪、改(Role表)
3.管理功能,對系統功能進行增、刪、改(Fun表)
由此可以分析,我們這個小系統需要的表為,User用戶表,Role角色表,Fun權限表,還要派生出一張表 角色-權限(RoleFun) 關聯表。其中用戶表里面有字段存放角色Role的ID。
一般情況下,我們都采用的是3層架構模式,即使是復雜模式也是在此基礎上延伸的。
上面這幅圖是最最基礎的一個框架。總共分為5個層次,Model層,DAL層,BLL層,Tools層,UI層
對於一般的編程者來說,實現起來並不復雜,可能不會將那么多的思想應用到實例中來,那么這里我們模擬下,先拋開這些思想。
(1)首先每個數據庫表對應一個Model類這個是必須的吧,那么我們在Model層新建4個類,User,Role,RoleFun,Fun
(2)這個四個對象都需要數據庫增、刪、改操作,那么我們在DAL里面對應的創建4個類,UserDAL,RoleDAL,RoleFunDAL,FunDAL,然后每個類里面寫入相同的方法,增、刪、改。
Insert(對象),Delete(對象),Update(對象)
這里你可能已經意識到問題了,hold,繼續看。
(3)同樣在BLL層要實現對DAL的調用,需要建立同樣的四個業務操作類,UserMgr,RoleMgr,RoleFunMgr,FunMgr,每個類里面實現同樣的調用方法。
(4)Tools暫不考慮,主要存放經常用的類
(5)UI層,表現層,可以是Web或者Winform等形式
搭建好的代碼框架如下:
面向對象的第一個特性是:封裝,其實我們已經實現了,分層就是封裝的最好體現,各層相互調用,“低耦合,高內聚”
這里不在解釋封裝了。
通過上面的代碼編寫你肯定遇見了災難了,當隨着我們業務功能的不斷增加,我們的DAL和BLL類越來越多,越來越難管理了。
更悲催的是,如果每個實體類我想實現一個查詢(Search)操作,那么需要在眾多的類里面實現這個Search代碼,試想那是多么的可怕,你的價值全部浪費在了基礎代碼的編寫上。
如何解決這個問題呢?
那就是采用繼承的思想實現,父子類來實現,一個公共的父類(BASE),所有子類繼承這個子類,那么子類也就具有了父類的public方法,如果需要增加公共的方法,只需要在父類中添加方法即可實現,所有子類自動會繼承。
模式如上圖所示,這樣實現一個Search()方法,我們只需要變動BaseDAL類即可,而其他實體類都不需要動了。試想對若干實體類的系統,這意思想是多么的重要,可以節省大量的時間。
還沒有結束,細心的你可能發現,我們的Insert,Update,Delete都需要自己的Model呀,那BaseDAL應該如何實現呢?怎么知道具體的方法去調用具體的Model呢?
哈哈,這里C#提出了引以為豪的“泛型”思想。通過泛型,可以輕松的解決這個問題。
對於BaseDAL我們可以設計成為泛型的類,在使用該類的時候需要將該類具體的實例化,看代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DAL { public class BaseDAL<T> where T:new () { public bool Insert(T t) { //TODO 解析T,通過反向工程構造SQL return true; } public bool Update(T t) { //TODO 解析T,通過反向工程構造SQL return true; } public bool Delete(T t) { //TODO 解析T,通過反向工程構造SQL return true; } } }
這樣,我們其他的類可以直接繼承父類了。但為了整體架構的可塑行,我們DAL層將不做對BaseDAL的繼承操作,原因很簡單,因為我們可能會切換DAL的技術,例如由ADO.Net切換成HNibernate等,同時DAL作為數據操作層盡量要保持簡約。
我們這里在業務邏輯層BLL來實現繼承,同樣也需要一個BaseBLL的基類。
using DAL; using System.Collections; using System.Collections.Generic; namespace BLL { public class BaseMgr<T> where T : new() { //可以重寫 public virtual bool Insert(T t) { return new BaseDAL<T>().Insert(t); } public bool Update(T t) { return new BaseDAL<T>().Update(t); } public bool Delete(T t) { return new BaseDAL<T>().Delete(t); } //重載 public bool Delete(List<T> list) { return true; } } }
然后具體的實體類繼承這個BaseMgr
using Model; namespace BLL { public class UserMgr : BaseMgr<User> //繼承 { //繼承基類最大的好處是,可以寫本類自己的特有方法 //例如User,我想獲取所有的用戶,而其他的業務邏輯不需要實現這個方法, //那么我們可以單獨寫在這個類里面 //當然你也可以寫在BaseMgr里面,哪樣所有的子類都具有這個方法了 //可以對基類進行重寫(多態) public override bool Insert(User t) { return true; } //繼承基類前的代碼 //public bool Insert(User t) //{ // return new UserDAL().Insert(t); //} //public bool Delete(User t) //{ // return new UserDAL().Delete(t); //} //public bool Update(User t) //{ // return new UserDAL().Update(t); //} } }
通過泛型實現繼承我們獲得的最大好處:
1,數據庫每增加一個實體,代碼的Model層只需要增加一個對應的實體類,那么該類的基礎操作隨即產生了(即,BaseDAL類的所有方法)
2,通過在業務層對基類的繼承,可以實現特有方法,當然並不是所有的實體類都需要繼承,具體看自己的需求
多態性(polymorphisn)是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
實現多態,有二種方式,覆蓋,重載。
覆蓋:override,上面代碼UserMgr類中的Insert方法就是用的覆蓋方法,可以重寫父類的某些方法來達到自己的業務要求。一定要注意將允許重寫的方法事先聲明為virtual
重載:通俗點就是一個方法名,不同的參數類型,例如我想實現一個批量刪除功能,方法的名字同樣想起名為Delete,那么只需要改變參數即可
public bool Delete(List<T> listT);
顧名思義,接口,即插即用,例如插座,只要有對應插頭,插入即可使用了。
接口:在編程里面起到的是一種規范,既然是規范,必定是約束若干人的,也就是團隊開發項目,大家共同遵循一個規范,協調開發代碼,而且互不干擾。
接口更多的是被軟件架構師使用,設計好整體的軟件架構,直接交給程序員開發即可,程序員只需要按照這種規范做就可以了,對每個接口進行具體的實現。
注意哦:接口不實現,是可以通過編譯的哦
通過采用上面的思想,基本上我們可以實現一套牢固的架構了,而且可以復用到任何的系統中。
但技術是在不斷革新的,而且需求也是不斷變化的,更可怕的是能夠運行系統的設備越來越多了,從PC到普通手機,再到智能手機(Android,IOS,WP7),再到平板電腦等等。
還有語言的差異,Java,php等等
這就要求一套架構不但要牢固,更能夠適用於各種平台的開發。
為此我們的架構可以引申成一個服務,將上面的架構在加上一個服務層(可以用WCF,可以用MVC4的WebAPI,Restful規范),那么整體的架構就是下面這個樣子了。
軟件開發其實就是一種思想,將人的一種思想通過代碼形式反映出來。好好用心思考,你就明白為什么會這么做,仔細體會其中的妙處。