本文版權歸博客園和做者吳雙本人共同全部。歡迎轉載,轉載和爬蟲請註明原文地址 http://www.cnblogs.com/tdws/p/5861842.htmlhtml
昨天晚上,有個朋友說學了很久,依然沒搞懂多態,讓我簡單講解一下。我以爲多態在面向多想的三大特性當中,算是最簡單的,最難的是看似容易的封裝。在編寫面向對象代碼時,如何讓代碼可讀性更強,除了變量和方法命名標準外,要作的到一個方法只作一件事情,這樣的思想是《代碼整潔之道》一書中主要推崇的思想,其實有經驗的各位都但願本身看到的代碼是簡短,可維護,可讀性強的,相信你們也都「有幸」遇到過幾百上千行的代碼,更過度的是有個朋友曾經維護一個上萬行的Action,誇張的說,調試並走通邏輯,一次要三天,有的人說這是業務邏輯不斷增長所致使,但我認爲,在這種狀況下,更應該儘可能作到一個方法作一件事情。我也很少吐槽了,關於代碼整潔,我在大三的時候,就"吐槽"過http://www.cnblogs.com/tdws/p/4674489.html。sql
封裝也不是今天的主題,今天咱們要說的是多態,在朋友問個人時候,我給他舉了下面這個簡短的例子。緩存
整體歸納這個例子來說就是在基本的三層架構當中,DAL層建兩個類AdminDal,UserDal。兩個類中,都有增長對象和刪除對象地方法,那這個時候,咱們應該給兩個類抽象出一個父類BaseDal<T>,父類中是他們的公共方法,而且父類須要一個泛型T,這樣父類的方法,才能明白你所要添加或者刪除的object究竟是什麼類型的。請看以下代碼。雖然兩個類的公共方法在父類當中,可是他們自身特有的方法,仍是要寫在本身的Dal層當中。服務器
1 public class UserDal: BaseDal<UserEntity> 2 { 3 4 }
1 public class AdminDal: BaseDal<AdminEntity> 2 { 3 public void Manage() 4 { 5 Console.WriteLine("管理員管理網站"); 6 } 7 }
1 public class BaseDal<T> 2 { 3 public void AddObj(T obj) 4 { 5 Console.WriteLine("添加對象成功,對象屬於"+obj.GetType().ToString()); 6 } 7 8 public void DeleteObj(T obj) 9 { 10 Console.WriteLine("刪除對象成功,對象屬於"+obj.GetType().ToString()); 11 } 12 13 }
下面給出邏輯層代碼,若是說普通的開發過程中,你的代碼也許是這樣的。架構
1 public class UserBll 2 { 3 UserDal dal = new UserDal(); 4 5 public void Add(UserEntity obj) 6 { 7 dal.AddObj(obj); 8 } 9 10 public void Delete(UserEntity obj) 11 { 12 dal.DeleteObj(obj); 13 } 14 }
public class AdminBll
{ AdminDal dal = new AdminDal(); public void Add(AdminEntity admin) { dal.AddObj(admin); } public void Delete(AdminEntity admin) { dal.DeleteObj(admin); } public void Manage() { dal.Manage(); } }
也就是在各自的邏輯層當中,調用dal層。這個時候你又看到依然有這麼多重複的代碼,是否是應該再次封裝成一個BaseBll<T>呢。答案是確定的,可是問題又來了,在封裝父類的過程當中,你會發現,這個dal的對象怎麼封裝呢?這就是用到多態的關鍵點。下面看一下BaseBll.cs的代碼。併發
public abstract class BaseBll<T> where T:class, new() { public BaseDal<T> currentDal; public BaseBll() { SetCurrentDal(); } public abstract void SetCurrentDal(); public void BaseAdd(T obj) { currentDal.AddObj(obj); } public void BaseDelete(T obj) { currentDal.DeleteObj(obj); } }
我給了一個抽象的基類,而且給出抽象的SetCurrentDal的抽象方法定義。該方法用於設置當前類的currentDal究竟是adminDal仍是userDal。咱們在構造函數中調用SetCurrentDal這個抽象方法,爲何在構造函數中調用的緣由是,當實例化子類對象時,必定是首先進入其父類的構造函數。當子類AdminBll和UserBll繼承BaseBll<T>的時候,必須重寫抽象方法,而且爲BaseDal<T> currentDal對象設置實際的值。我先給出子類的代碼app
1 public class AdminBll : BaseBll<AdminEntity> 2 { 3 AdminDal dal = new AdminDal(); 4 public AdminBll() 5 { 6 7 } 8 public void Manage() 9 { 10 new AdminDal().Manage(); 11 } 12 13 public override void SetCurrentDal() 14 { 15 currentDal = new AdminDal(); 16 } 17 }
1 public class UserBll : BaseBll<UserEntity> 2 { 3 public override void SetCurrentDal() 4 { 5 base.currentDal = new UserDal(); 6 } 7 }
當實例化子類的對象時,過程爲:子類構造函數(不進入)—進入父類構造函數—父類構造內部調用子類重寫的SetCurrentDal(當前多態的currentDal究竟是誰的實例)—父類構造執行完畢(設置currentDal完成)—子類構造函數。這就是抽象方法實現的多態。框架
下面在UI層調用一下,看看結果:ide
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 AdminBll adminBll = new AdminBll(); 6 AdminEntity admin = new AdminEntity() {AdminName="吳雙",AdminPwd="123" }; 7 adminBll.Manage(); 8 adminBll.BaseAdd(admin); 9 Console.ReadKey(); 10 } 11 }
輸出結果:函數
在開發的過程當中,也許你會有不少實體類,每一個實體類都有各自的增刪改查等其餘共有方法,基於這樣的狀況,咱們就須要手段來將其封裝。爲何在邏輯層使用了多態,緣由就是咱們封裝父類的時候,不肯定當前的currentDal究竟是adminDal仍是userDal仍是xxxDal。爲了封裝出基類,這個多態的對象就必不可少了。
固然在實際當中,若是你是寫原生sql,這樣封裝的確不容易,各類拼接sql。但若是說你用ORM框架,EF,Dapper之類的,這個方法真的是必不可少的,你可能再加上接口層,加上工做單元,建立對象非new,使用抽象工廠,依賴注入等。不管怎樣,這一層的多態必定能用到,只是建立對象稍做修改。
下一階段也打算進行後臺架構搭建分享,MVC WebApi+EF/Dapper+工做單元+抽象工廠/依賴注入Autofac+AutoMapper+日誌組件等。
我也曾屢次在項目中搭建此類框架,在緩存提升性能,處理高併發,應用服務器集羣,緩存集羣,隊列集羣等方面,本次也會加入到分享當中。
若是今天的點滴分享,對您有點滴幫助,請點贊支持,也爲本身的進步點贊。
點擊下方關注,咱們共同進步。