值得永久收藏的 C# 设计模式套路(一)
設計模式知道,套路是個啥?
關于設計模式的說法,網上一搜一大堆,咱就不再去說了。
我的理解,設計模式就是很多NB的大佬們總結出來的,用來處理特定情況的標準解決方案。
那既然是標準方案,就一定會有套路,會有標準的樣子。
幾種常見的設計模式,都有各自的套路模板。下面進入主題,咱們一個一個來說。
一、抽象工廠模式
抽象工廠主要的場景是創建一系列相關或相似的對象。注意這個相關或相似。因為有這個特性,我們就可以抽取出共同點,來形成接口或抽象類,然后通過這個接口或抽象類,來派生出各個對象。
為什么叫抽象工廠?不知道,而且不重要。在我看來,這只是個名字,記下就好。一個東西出來,總要有個名字的,有個人跑出來說,就叫抽象工廠吧。于是就叫抽象工廠了。就像一個人,做了一個網站,讓別人在上面賣東西,后來做大了,需要吹NB了,得給這個經營方式起個名字,于是,B2C 就出現了?,F在人們創業做電商,頭一件事先討論做 B2B 還是 B2C。做反了。先做吧,掙錢要緊。做大了,你說叫什么,都會有人聽、有人信。
說跑題了,:P
先寫幾個類型,包括接口和實體類,后面會用到:
//?接口定義 public?interface?ILaptop {void?GetInfo(); } public?interface?IMobile {void?GetInfo(); }//?實體類一 public?class?MateBook?:?ILaptop {public?void?GetInfo(){Console.WriteLine("I?am?MateBook");} } public?class?Mac?:?ILaptop {public?void?GetInfo(){Console.WriteLine("I?am?Mac");} }//?實體類二 public?class?Mate?:?IMobile {public?void?GetInfo(){Console.WriteLine("I?am?Mate");} } public?class?IPhone?:?IMobile {public?void?GetInfo(){Console.WriteLine("I?am?IPhone");} }有了上面的類型,我們來看看抽象工廠的套路。
定義:
public?interface?IFactory {ILaptop?CreateLaptop();IMobile?CreateMobile(); } public?class?FactoryA?:?IFactory {public?ILaptop?CreateLaptop(){return?new?MateBook();}public?IMobile?CreateMobile(){return?new?Mate();} } public?class?FactoryB?:?IFactory {public?ILaptop?CreateLaptop(){return?new?Mac();}public?IMobile?CreateMobile(){return?new?IPhone();} }調用:
public?static?class?Example {public?static?void?ExampleTest(){var?factoryA?=?new?FactoryA();var?laptopA?=?factoryA.CreateLaptop();var?mobileA?=?factoryA.CreateMobile();laptopA.GetName();mobileA.GetName();var?factoryB?=?new?FactoryB();var?laptopB?=?factoryB.CreateLaptop();var?mobileB?=?factoryB.CreateMobile();laptopB.GetName();mobileB.GetName();}//result?://I?am?MateBook//I?am?Mate//I?am?Mac//I?am?IPhone }這個模式里面,核心的部分就是工廠接口的定義:
public?interface?IFactory {ILaptop?CreateLaptop();IMobile?CreateMobile(); }在這個工廠接口中,加入了多個相似的接口。于是,調用端可以很簡單的以類似的方式去調用,而工廠實體中,對內部引用的實體進行區分。一個典型的場景是:一個程序,對著很多種數據庫。這樣的情況,可以在工廠實體中區分具體連接哪種數據庫,而內部的引用實體,則各自對應不同的數據庫。外部調用時,只需要在初始化時確認使用哪種數據庫,后面的 CRUD 操作,就直接使用就成,調用端不需要考慮數據庫的區別。事實上,這也是抽象工廠用的最多的場景。
二、工廠模式
去掉了抽象兩個字,居然還是一個模式,而且是一個不同的模式。這個名字起的夠混亂。
不過老實說,工廠模式跟抽象工廠模式很像,區別是:抽象工廠模式是在工廠模式的基礎上,又做了一層抽象。
看套路:
public?interface?IFactory {ILaptop?CreateLaptop(); } public?class?FactoryA?:?IFactory {public?ILaptop?CreateLaptop(){return?new?MateBook();} } public?class?FactoryB?:?IFactory {public?ILaptop?CreateLaptop(){return?new?Mac();} } public?static?class?Example {public?static?void?Test(){var?factoryA?=?new?FactoryA();var?laptopA?=?factoryA.CreateLaptop();laptopA.GetName();var?factoryB?=?new?FactoryA();var?laptopB?=?factoryB.CreateLaptop();laptopB.GetName();}//result?://I?am?MateBook//I?am?Mac }看到了吧,跟抽象工廠確實很相似。不過在使用上,工廠模式用得會更多。任何類都可以按工廠模式來寫。這個模式最大的作用,是把定義和實體做了分層。開發時,可以一部分人去定義接口,而另一部分人去實現這個接口。而且,工作模式可以隨時擴展為抽象工廠。比方一開始只是可能有多種數據庫,但具體是哪些數據庫還沒確定,就可以先按工廠模式寫,等數據庫定下來,隨時就很容易轉為抽象工廠了。
三、建造者模式
這個名稱起的更不知所云了,就因為一個 Builder?
其實他說的是這么個事。我們經??吹竭@樣的代碼:
var?mobile?=?new?MobileBuilder().WithBrand("Apple").WithModel("13Pro").WithMemory("512G").Build();看著是不是很洋氣?
來看看這個套路:
//?這就是個數據模型 public?class?Mobile {public?string?Brand?{?get;?set;?}public?string?Model?{?get;?set;?}public?string?Memory?{?get;?set;?} }//?這才是?Builder?的定義 public?class?MobileBuilder {private?readonly?Mobile?_mobile?=?new?Mobile();public?MobileBuilder?WithBrand(string?brand){_mobile.Brand?=?brand;return?this;}public?MobileBuilder?WithModel(string?model){_mobile.Model?=?model;return?this;}public?MobileBuilder?WithMemory(string?memory){_mobile.Memory?=?memory;return?this;}public?Mobile?Build(){return?_mobile;} }然后就可以這樣調用了:
public?static?class?Example {public?static?void?Test(){var?mobile?=?new?MobileBuilder().WithBrand("Apple").WithModel("13Pro").WithMemory("512G").Build();Console.WriteLine(mobile.ToJson());}//result?://{"Brand":"Apple","Model":"13Pro","Memory":"512G"} }個人而言,我很喜歡這個套路,沒有別的,就是洋氣,非常的洋氣。應用場景也非常多,所有數據的 DTO,都可以么寫。
四、原型模式
這個模式聽著會有點陌生??催^一些文章,也把它歸為是創建型模式。實際上,我更傾向于把它看作是一種代碼結構,而不是模式。這種結構最大的作用,是復制 - 通過復制一個存在的實例來創建新實例。
代碼是這樣的:
public?class?MobilePackage {public?string?Color?{?get;?set;?}public?Mobile?Mobile?{?get;?set;?}//?下面才是模式代碼public?MobilePackage?ShallowCopy(){return?(MobilePackage)this.MemberwiseClone();}public?MobilePackage?DeepCopy(){var?clone?=?(MobilePackage)this.MemberwiseClone();clone.Color?=?new?string(Color);clone.Mobile?=?new?Mobile{Brand?=?new?string(Mobile.Brand),Model?=?new?string(Mobile.Model),Memory?=?new?string(Mobile.Memory),};return?clone;} }看看,其實就是一段復制代碼。
但是要注意,對于深拷貝和淺拷貝,涉及到指針和引用,如果你不熟悉,了解后再用??匆幌律厦娴慕Y果:
public?static?class?Example {public?static?void?Test(){var?mobilePackage?=?new?MobilePackage{Color?=?"White",Mobile?=?new?Mobile{Brand?=?"Apple",Model?=?"13Pro",Memory?=?"512G",}};var?shallowCopied?=?mobilePackage.ShallowCopy();var?deepCopied?=?mobilePackage.DeepCopy();mobilePackage.Color?=?"Black";mobilePackage.Mobile.Brand?=?"Huawei";mobilePackage.Mobile.Model?=?"Mate";Console.WriteLine(mobilePackage.ToJson());Console.WriteLine(shallowCopied.ToJson());Console.WriteLine(deepCopied.ToJson());}//result://{"Color":"Black","Mobile":{"Brand":"Huawei","Model":"Mate","Memory":"512G"}}//{"Color":"White","Mobile":{"Brand":"Huawei","Model":"Mate","Memory":"512G"}}//{"Color":"White","Mobile":{"Brand":"Apple","Model":"13Pro","Memory":"512G"}} }結果和你理解的是不是一樣?如果不一樣,去研究一下值和引用的區別。另外,C# 10 里新出來的 Record,就是一個典型的原型模式的類型,也可以了解一下。
五、單例模式
單例模式也是一個用處非常大的模式,而且這個名字起得挺直白。
單例模式,簡單點說就是不管你 new 多少回,實際應用全局內存中只會有一份實例。
套路代碼特別簡單:
public?sealed?class?Singleton {private?static?Singleton?_instance;private?static?readonly?object?_locker?=?new?object();private?Singleton(){}public?static?Singleton?GetInstance(){if?(_instance?==?null){lock?(_locker){if?(_instance?==?null){_instance?=?new?Singleton();}}}return?_instance;} }這里有兩個注意點:
類聲明用到 sealed 關鍵字,以確保這個類不會被派生。
類構造函數用了 private,以確保這個類不會被 new。這本身與單例無關,只是通過這種方式來表明這是一個單例??刂茊卫淖詈诵牡拇a,其實是下面的 GetInstance() 方法。
調用時,就是下面一行代碼:
Singleton?singleton?=?Singleton.GetInstance();就OK了。
設計模式有很多種,對應的套路也有很多。其中,有一些是簡單無腦的套路,像上面的單例,而另一些就會比較復雜。
不過,既然是套路,總是有固定的代碼或結構可循的。
我這個主題,打算分幾篇來寫。這是第一篇。
最后做個小注解:套路雖簡單,也要吃透了再用。而且,有時候簡單的代碼就能很好地完成任務,一定不要過度使用。
喜歡就來個三連,讓更多人因你而受益
總結
以上是生活随笔為你收集整理的值得永久收藏的 C# 设计模式套路(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 精彩回顾 | Dapr闪电说系列
- 下一篇: c# char unsigned_dll