目錄
- 什么是設計模式
- 創建型模式
- 單例模式(Singleton Pattern)
- 原型模式(Prototype Pattern)
- 工廠模式(Factory Pattern)
- 簡單工廠模式(Sinple Factory Pattern)
- 工廠方法模式(Factory Method Pattern)
- 抽象工廠(Abstract Factory)
- 工廠模式總結
前言:相信作為程式開發,或多或少都接觸甚至使用過設計模式,甚至對于有些設計模式的概念都已經很熟悉了,但是在實際開發專案的時候是否有使用過這些模式呢,可能比較少甚至沒有,有些設計模式確實在架構中更實用一些,這也是部分原因,但不管怎樣,最起碼常用的幾種設計模式還是需要了解的,本文介紹幾種常見的設計模式,希望讀者能從中有所識訓并學以致用,
什么是設計模式
設計模式(Design Pattern)是前輩們對代碼開發經驗的總結,是解決特定問題的一系列套路,它不是語法規定,而是一套用來提高代碼 可復用性 、 可維護性 、可讀性、穩健性以及安全性的解決方案,
假設有一個空房間,我們要日復一日地往里 面放一些東西,最簡單的辦法當然是把這些東西 直接扔進去,但是時間久了,就會發現很難從這 個房子里找到自己想要的東西,要調整某幾樣東 西的位置也不容易,所以在房間里做一些柜子也 許是個更好的選擇,雖然柜子會增加我們的成 本,但它可以在維護階段為我們帶來好處,使用 這些柜子存放東西的規則,或許就是一種模式,
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名為 Design Patterns - Elements of Reusable Object-Oriented Software(中文譯名:設計模式 - 可復用的面向物件軟體元素) 的書,該書首次提到了軟體開發中設計模式的概念,
四位作者合稱 GOF(四人幫,全拼 Gang of Four),他們所提出的設計模式主要是基于以下的面向物件設計原則,
- 對介面編程而不是對實作編程——依賴倒置原則
- 優先使用物件組合而不是繼承——合成復用原則,
設計模式的六大原則:
- 單一職責原則(Single Responsibility Principle),職責清晰
- 里氏替換原則(Liskov Substitution Principle)——任何使用基類的地方,都可以透明的使用其子類
- 迪米特法則 (Law Of Demeter)—— 一個物件應該對其他物件保持最少的了解,即高聚合低耦合
- 依賴倒置原則(Dependence Inversion Principle)—— 依賴抽象,而不是依賴細節
- 介面隔離原則(Interface Segregation Principle)—— 客戶端不應該依賴它不需要的介面; 一個類對另一個類的依賴應該建立在最小的介面上;
- 開閉原則 (Open Closed Principle) —— 對擴展開發,對修改關閉
創建型模式
單例模式(Singleton Pattern)
單例模式想必大家都已經耳熟能詳了,這是很常見的一種設計模式,也是最簡單的一種設計模式,它提供了一種創建物件的最佳方式,這種模式涉及到一個單一的類,該類負責創建自己的物件,同時確保只有單個物件被創建,這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要實體化該類的物件,
使用單例模式的實體:.NET Core依賴注入生命周期中的Singleton,生命周期為Singleton的服務全域唯一,每次呼叫都是呼叫的同一個服務.
單例模式有兩種寫法,懶漢式和餓漢式,
懶漢式,顧名思義,比較懶,一開始的時候不會創建物件,要用到了才會想起來去創建物件,寫法如下:
//懶漢式單例寫法
public class SingletonPattern
{
private static SingletonPattern _singletonInstance;
//建構式私有化是關鍵
private SingletonPattern()
{
}
//雙重檢驗,提升性能
public static SingletonPattern GetInstance(bool useLock = true)
{
if (_singletonInstance is null)
{
lock (singleton_lock)
{
if (_singletonInstance is null)
{
_singletonInstance = new SingletonPattern();
}
}
}
return _singletonInstance;
}
}
注意:懶漢式要考慮多執行緒安全問題,這里使用雙重檢驗鎖以確保執行緒安全并提升性能
餓漢式比較簡單,只需要做個是否已經創建的判斷即可,寫法如下:
//餓漢式單例寫法
public class SingletonPattern
{
private static SingletonPattern _singletonInstance = new SingletonPattern();
//建構式私有化是關鍵
private SingletonPattern()
{
}
public static SingletonPattern GetInstance(bool useLock = true)
{
if (_singletonInstance is null)
{
_singletonInstance = new SingletonPattern();
}
return _singletonInstance;
}
}
該模式的適用場景:
- 一個全域類,頻繁創建和銷毀,如服務類、工具類等
- 需要控制實體數量,節約系統資源的時候
原型模式(Prototype Pattern)
原型模式(Prototype Pattern)是用于創建重復的物件,同時又能保證性能,這種型別的設計模式屬于創建型模式,它提供了一種創建物件的最佳方式,這種模式是實作了一個原型介面,該介面用于創建當前物件的克隆,當直接創建物件的代價比較大時,則采用這種模式,例如,一個物件需要在一個高代價的資料庫操作之后被創建,我們可以快取該物件,在下一個請求時回傳它的克隆,在需要的時候更新資料庫,以此來減少資料庫呼叫,
原型模式的難點在于對物件的克隆,如果物件比較復雜,嵌套的屬性物件比較多,自己實作克隆方法會比較麻煩,不過還好目前主流語言都支持深度克隆物件,如Java的Serializable, javascript的cloneDeep等等,深度克隆也可以通過序列化和反序列化來實作,因此支持序列化和反序列化的語言都可以用這種方式實作深度克隆,
原型的實作方式與單例相差不大,重點是回傳的實體是克隆物件
public class PrototypePattern
{
private static PrototypePattern _protetypeInstance = new PrototypePattern();
private PrototypePattern()
{
}
public static PrototypePattern GetInstance()
{
//重點在于回傳克隆的物件
PrototypePattern clone = GetDeepCloneObj();
return clone;
}
}
原型適用場景:
- 物件創建復雜,消耗資源大,又需要重復創建類似物件
工廠模式(Factory Pattern)
工廠模式在GOF的設計模式中分為工廠方法和抽象工廠,實際上簡單工廠、工廠方法和抽象工廠的分類更為普遍一些,
簡單工廠模式(Sinple Factory Pattern)
簡單工廠主要隔離了使用者和產品,使用者需要使用產品時,直接向工廠請求,而不用知道具體產品的實作,也就是前面說的依賴倒置原則!

上圖可以看出,用戶要創建一個產品,不需要知道產品的具體實作,只需要知道創建產品的工廠即可,實作代碼如下:
public class SimpleFactoryPattern
{
public static IRunner CreateRunner(PatternEnum pattern)
{
switch (pattern)
{
case PatternEnum.Singleton:
return new SingletonRunner();
case PatternEnum.Prototype:
return new PrototypeRunner();
case PatternEnum.Factory_Method:
return new FactoryMethodRunner();
case PatternEnum.Abstract_Factory:
return new AbstractFactoryRunner();
default:
return null;
}
}
}
//使用
class Program
{
static void Main(string[] args)
{
var pattern = PatternEnum.Abstract_Factory;
var prototype = SimpleFactoryPattern.CreateRunner(pattern);
prototype.Run();
Console.ReadKey();
}
}
簡單工廠適用于比較簡單的情況下,可以屏蔽物件創建細節,對于物件來說符合開閉原則,但是對于工廠來說并不符合開閉原則,因為當需要新增一個物件時,需要修改工廠的內容,另外當需要生成的物件過多時或者經常需要修改時,該模式就顯得不夠用了,
這時候就需要使用工廠方法了
工廠方法模式(Factory Method Pattern)

如上圖,工廠方法相比于簡單工廠,改變在于將具體的工廠也屏蔽了,用戶不需要知道需要用什么工廠,只要呼叫抽象工廠的方法即可,實作如下:
//抽象工廠
public abstract class MounseFactoryMethod
{
public abstract IMouse CreateMouse();
}
//具體實作工廠
public class DellMouseFactory : MounseFactoryMethod
{
public override IMouse CreateMouse()
{
return new DellMouse();
}
}
//具體實作工廠
public class HpMouseFactory : MounseFactoryMethod
{
public override IMouse CreateMouse()
{
return new HpMouse();
}
}
//當具體的實作工廠太多時,可以結合簡單工廠,利用簡單工廠創建具體工廠
//也可以利用反射創建工廠
public class MouseFactory
{
public static MounseFactoryMethod CreateMouseFactory(BrandEnum brand)
{
switch (brand)
{
case BrandEnum.Dell:
return new DellMouseFactory();
case BrandEnum.Hp:
return new HpMouseFactory();
default:
return null;
}
}
}
//使用
class Program
{
static void Main(string[] args)
{
var mouseFactory = MouseFactory.CreateMouseFactory(BrandEnum.Dell);
var mouse = mouseFactory.CreateMouse();
mouse.Click();
}
}
工廠方法的工廠是符合開閉原則的,當有新產品時,只需要添加新的工廠即可,不需要改動已有工廠代碼,
在上面的代碼中,我們抽象了一個滑鼠生產工廠MounseFactoryMethod,兩個具體生產工廠DellMouseFactory 和HpMouseFactory ,另外還額外使用了一個簡單工廠MouseFactory來選擇要使用的具體工廠,
工廠方法在實際使用中比較常見,當需要創建的物件種類比較多且新增或洗掉比較頻繁時,工廠方法是不錯的選擇,
抽象工廠(Abstract Factory)
首先了解下產品族的概念:

如上圖,擁有相同特性的產品稱為一個產品等級,同一產品平臺的不同產品稱為一個產品族,
抽象工廠用于處理比較復雜的產品,舉個例子,上述工廠方法中的MounseFactoryMethod專門用于生產滑鼠,而DellMouseFactory 和HpMouseFactory 則分別用于生產戴爾滑鼠和惠貧訓鼠,它們都是一個產品等級的產品,當我們不僅需要生產滑鼠,還要生成鍵盤時,光是一個MounseFactoryMethod已經不能滿足生產需要,這時候工廠生產的就不只是單一產品,而是一個產品族,類圖如下:

上圖中,我們定義了一個ComputerFactory,這個工廠能夠生產更豐富的產品(滑鼠和鍵盤),戴爾和惠普分別有獨立的工廠生產自己的滑鼠和鍵盤,
像上圖這種,生產產品族的工廠稱為抽象工廠,
抽象工廠和工廠方法的區別在于,工廠方法只能生產單一產品,也就是產品介面只有一個,而抽象工廠的產品可能是來自不同的介面,
實作代碼如下:
public abstract class ComputerAbstractFactory
{
public abstract IMouse CreateMouse();
public abstract IKeyboard CreateKeyboard();
}
public class DellAbstractFactory : ComputerAbstractFactory
{
public override IKeyboard CreateKeyboard()
{
return new DellKeyboard();
}
public override IMouse CreateMouse()
{
return new DellMouse();
}
}
public class HpAbstractFactory : ComputerAbstractFactory
{
public override IKeyboard CreateKeyboard()
{
return new HpKeyboard();
}
public override IMouse CreateMouse()
{
return new HpMouse();
}
}
//使用
class Program
{
static void Main(string[] args)
{
Console.WriteLine("使用抽象工廠 DellAbstractFactory 創建產品");
var dellFactory = new DellAbstractFactory();
dellFactory.CreateKeyboard().Click();
dellFactory.CreateMouse().Click();
Console.WriteLine("使用抽象工廠 HpAbstractFactory 創建產品");
var hpFactory = new HpAbstractFactory();
hpFactory.CreateKeyboard().Click();
hpFactory.CreateMouse().Click();
}
}
工廠模式總結
- 簡單工廠不符合開閉原則,僅使用于產品種類少、修改不頻繁的情況
- 工廠方法符合開閉原則,但只適用單一產品等級的情況
- 抽象工廠符合開閉原則,適用于生產產品族的情況
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/464947.html
標籤:.NET技术
