本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7567880.html,記錄一下學習程序以備后續查用,
一、引言
接上一篇C#設計模式學習筆記:簡單工廠模式(工廠方法模式前奏篇),通過簡單工廠模式的了解,它的缺點就是隨著需求的變化我們要不停地修改工廠里
面的方法的代碼,需求變化越多,里面的if--else也越多,這樣就會造成簡單工廠的實作邏輯過于復雜,
依設計原則里的開閉原則--對增加代碼開放,對修改代碼關閉,我們不能總是這樣修改簡單工廠里面的方法,
下面看看工廠方法模式是如何解決該問題的?
二、工廠方法模式介紹
工廠方法模式:英文名稱--Factory Method Pattern;分類--創建型,
2.1、動機(Motivate)
在軟體系統的構建程序中,經常面臨著“某個物件”的創建作業:由于需求的變化,這個物件(的具體實作)經常面臨著劇烈的變化,但是它卻擁有比
較穩定的介面,
如何應對這種變化?如何提供一種“封裝機制”來隔離出“這個易變物件”的變化,從而保持系統中“其他依賴物件的物件”不隨著需求改變而改變?
2.2、意圖(Intent)
定義一個用于創建物件的介面,讓子類決定實體化哪一個類,Factory Method使得一個類的實體化延遲到子類,--《設計模式》GoF
2.3、結構圖(Structure)

2.4、模式的組成
從上圖可以看出,在工廠方法模式的結構圖有以下角色:
1)抽象工廠角色(Creator):充當抽象工廠角色,定義工廠類所具有的基本的操作,任何具體工廠都必須繼承該抽象類,
2)具體工廠角色(ConcreteCreator):充當具體工廠角色,該類必須繼承抽象工廠角色,實作抽象工廠定義的方法,用來創建具體產品,
3)抽象產品角色(Product):充當抽象產品角色,定義了產品型別所有具有的基本操作,具體產品必須繼承該抽象類,
4)具體產品角色(ConcreteProduct):充當具體產品角色,實作抽象產品類對定義的抽象方法,由具體工廠類創建,它們之間有一一對應的關系,
2.5、工廠方法模式的具體實作
面向物件設計三大原則:
1)哪里有變化就封裝哪里,
2)面向抽象編程,細節和高層實作都要依賴抽象,
3)多組合,少繼承,
這三大原則是最根本的原則,學習設計模式必須以這三個原則為基點,否則都是枉然,根據這三大原則又衍生出來6個具體的原則,分別是單一職責
原則、開閉原則、里氏替換原則、依賴倒置原則、介面隔離原則、迪米特法則,
既然工廠類有變化,我們就封裝它,面向抽象編程,我們先抽象出一個工廠基類,然后每個需求都實作一個具體的工廠類,這樣我們就符合了開閉原
則,讓一個工廠生產一款產品,并一一對應,具體產品的創建推遲到子類中,此時工廠類(基類)不再負責所有產品的創建,而只是給出具體工廠必須
實作的介面,這樣工廠方法模式就可以允許系統不修改工廠類邏輯的情況下來添加新產品,也就克服了簡單工廠模式中缺點,
下面是工廠方法模式的實作代碼:
class Program { /// <summary> /// 汽車抽象類 /// </summary> public abstract class Car { //開始行駛 public abstract void Go(); } /// <summary> /// 紅旗汽車 /// </summary> public class HongQiCar : Car { public override void Go() { Console.WriteLine("紅旗汽車生產中,"); } } /// <summary> /// 奧迪汽車 /// </summary> public class AoDiCar : Car { public override void Go() { Console.WriteLine("奧迪汽車生產中,"); } } /// <summary> /// 抽象工廠類 /// </summary> public abstract class Factory { //工廠方法 public abstract Car CreateCar(); } /// <summary> /// 紅旗汽車工廠類 /// </summary> public class HongQiCarFactory : Factory { /// <summary> /// 負責生產紅旗汽車 /// </summary> /// <returns></returns> public override Car CreateCar() { return new HongQiCar(); } } /// <summary> /// 奧迪汽車工廠類 /// </summary> public class AoDiCarFactory : Factory { /// <summary> /// 負責創建奧迪汽車 /// </summary> /// <returns></returns> public override Car CreateCar() { return new AoDiCar(); } } static void Main(string[] args) { #region 工廠方法模式 //初始化創建汽車的兩個工廠 Factory hongQiCarFactory = new HongQiCarFactory(); Factory aoDiCarFactory = new AoDiCarFactory(); //生產一輛紅旗汽車 Car hongQi = hongQiCarFactory.CreateCar(); hongQi.Go(); //生產一輛奧迪汽車 Car aoDi = aoDiCarFactory.CreateCar(); aoDi.Go(); Console.Read(); #endregion } }View Code
運行結果如下:

使用工廠方法實作的系統,如果系統需要添加新產品時,我們可以利用多型性來完成系統的擴展,對于抽象工廠類和具體工廠中的代碼都不需要做任
何改動,假如我們想生產奔馳車,我們只需從Car抽象類下繼承一個BenChiCar類、在Factory抽象類下繼承一個“奔馳”的工廠類BenChiCarFactory就可
以實作了:
class Program { /// <summary> /// 汽車抽象類 /// </summary> public abstract class Car { //開始行駛 public abstract void Go(); } /// <summary> /// 紅旗汽車 /// </summary> public class HongQiCar : Car { public override void Go() { Console.WriteLine("紅旗汽車生產中,"); } } /// <summary> /// 奧迪汽車 /// </summary> public class AoDiCar : Car { public override void Go() { Console.WriteLine("奧迪汽車生產中,"); } } /// <summary> /// 奔馳汽車 /// </summary> public class BenChiCar : Car { public override void Go() { Console.WriteLine("奔馳汽車生產中,"); } } /// <summary> /// 抽象工廠類 /// </summary> public abstract class Factory { //工廠方法 public abstract Car CreateCar(); } /// <summary> /// 紅旗汽車工廠類 /// </summary> public class HongQiCarFactory : Factory { /// <summary> /// 負責生產紅旗汽車 /// </summary> /// <returns></returns> public override Car CreateCar() { return new HongQiCar(); } } /// <summary> /// 奧迪汽車工廠類 /// </summary> public class AoDiCarFactory : Factory { /// <summary> /// 負責創建奧迪汽車 /// </summary> /// <returns></returns> public override Car CreateCar() { return new AoDiCar(); } } /// <summary> /// 奔馳汽車工廠類 /// </summary> public class BenChiCarFactory : Factory { /// <summary> /// 負責生產奔馳汽車 /// </summary> /// <returns></returns> public override Car CreateCar() { return new BenChiCar(); } } static void Main(string[] args) { #region 工廠方法模式 //初始化創建汽車的兩個工廠 Factory hongQiCarFactory = new HongQiCarFactory(); Factory aoDiCarFactory = new AoDiCarFactory(); Factory benChiCarFactory = new BenChiCarFactory(); //生產一輛紅旗汽車 Car hongQi = hongQiCarFactory.CreateCar(); hongQi.Go(); //生產一輛奧迪汽車 Car aoDi = aoDiCarFactory.CreateCar(); aoDi.Go(); //生產一輛奔馳汽車 Car benChi = benChiCarFactory.CreateCar(); benChi.Go(); Console.Read(); #endregion } }View Code
運行結果如下:

三、Factory Method模式的幾個要點
Factory Method模式主要用于隔離類物件的使用者和具體型別之間的耦合關系,面對一個經常變化的具體型別,緊耦合關系會導致軟體的脆弱;
Factory Method模式通過面向物件的手法,將所要創建的具體物件作業延遲到子類,從而實作一種擴展(而非更改)的策略,較好地解決了這種緊耦
合關系;
Factory Method模式解決“單個物件”的需求變化;
AbstractFactory模式解決“系列物件”的需求變化;
Builder模式解決“物件部分”的需求變化;
3.1、工廠方法模式的優點
1)在工廠方法中,用戶只需要知道所要產品的具體工廠,無須關心具體的創建程序,甚至不需要具體產品類的類名,
2)在系統增加新的產品時,我們只需要添加一個具體產品類和對應的實作工廠,無需對原工廠進行任何修改,很好地符合了“開閉原則”,
3.2、工廠方法模式的缺點
1)每次增加一個產品時,都需要增加一個具體類和物件實作工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的復雜度,同時也增加
了系統具體類的依賴,這并不是什么好事,
3.3、工廠方法模式的使用場合
1)一個類不知道它所需要的物件的類,在工廠方法模式中,我們不需要具體產品的類名,我們只需要知道創建它的具體工廠即可,
2)一個類通過其子類來指定創建那個物件,在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的介面,由其子類來確定具體要創建的對
象,在程式運行時,子類物件將覆寫父類物件,從而使得系統更容易擴展,
3)將創建物件的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,
四、.NET中實作了工廠方法的類
.NET類別庫中也有很多實作了工廠方法的類,例如在Asp.net中,處理程式物件是具體用來處理請求,當我們請求一個*.aspx的檔案時,此時會映射到
System.Web.UI.PageHandlerFactory類上進行處理,而對*.ashx的請求將映射到System.Web.UI.SimpleHandlerFactory類中(這兩個類都是繼承于
IHttpHandlerFactory介面的),關于這點說明我們可在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”檔案中找到相關定義:
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>
上面只摘選了部分組態檔,有時間大家可以自己去研究一下,
下面我們具體看下工廠方法模式在Asp.net中是如何實作的?對一個Index.aspx頁面發出請求時,將會呼叫PageHandlerFactory中GetHandler方法來
創建一個Index.aspx物件,它們之間的類圖關系如下:

五、總結
每種模式都有自己的使用場合,切記,如果使用錯誤,還不如不用,工廠方法模式通過面向物件編程中的多型性來將物件的創建延遲到具體工廠中,
從而解決了簡單工廠模式中存在的問題,也很好地符合了開放封閉原則(即對擴展開發,對修改封閉),
學習設計模式我們一定要謹記設計模式的幾大原則,否則是徒勞無功的,就像學務工一樣,我們要記心法,幾大原則就像獨孤九劍的劍訣,學會了,
變化無窮,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/81879.html
標籤:C#
上一篇:IEnumerable、ICollection、IList、List關系和區別
下一篇:C# 如何獲取日期時間各種方法
