總體介紹:
工廠模式主要有三種型別:簡單工廠、工廠方法和抽象工廠,該模式用於封裝和管理物件的建立,是一種建立型模式。
萬物皆物件,建立物件時必然需要new該物件,當需要更改物件時,需要把專案中所有地方都修改一遍,這顯然違背了軟體設計的開閉原則。
如果使用工廠來生成物件,那麼我們只需要跟工廠打交道就可以了。如果要更新物件時,直接在工廠裡更換即可。這就實現了物件解耦。
所以工廠模式主要用來解耦程式碼,將物件的建立和使用分離,使得程式碼更加靈活和可維護。
定義建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。
適用於建立物件需要大量重複的步驟,或者需要依賴於其它物件的情況,它提供了一種方式來封裝多個相關或依賴物件的建立邏輯。
(一)簡單工廠基礎介紹:
這是工廠模式的最基本形式,透過定義一個工廠類,它可以根據引數的不同返回不同類的例項,被建立的例項通常都具有共同的父類。
因為在簡單工廠模式中用於建立例項的方法是靜態(static)方法,因此簡單工廠模式又被稱為靜態工廠方法模式,它屬於類建立型模式,但不屬於GOF23種設計模式。
簡單工廠包含三大角色:
- 抽象產品(抽象類):定義了產品的規範,描述了產品的主要特徵和功能。它是工廠類建立的所有物件的父類,封裝了各種產品物件的共有方法。
- 具體產品(子類):繼承抽象產品的子類,某個產品的具體實現類。
- 具體工廠(例項化物件類):它是簡單工廠模式的核心,負責實現建立所有產品例項的內部邏輯;其可以被外界直接呼叫,建立所需的產品物件。
- 特性和功能:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。
- 使用環境:當一個類不知道它所必須建立的物件的類的時候。
- 注意事項:每增加一個產品就需要增加一個具體類和物件實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度。
- 優點:一個呼叫者想建立一個物件,只要知道其名稱就可以了。
- 缺點:增加新的產品需要修改工廠介面,違背了“開放-封閉原則”。
簡單工廠建立方式:
- 首先定義一個抽象產品類。
1 /// <summary> 2 /// 該類是產品的父類即抽象產品,定義所有子類的共有屬性和方法 3 /// </summary> 4 public abstract class Coffee 5 { 6 /// <summary> 7 /// 方便演示,只定義兩個代表性方法。 8 /// </summary> 9 public abstract void GetName(); 10 11 public void AddSugar() 12 { 13 Console.WriteLine("加糖"); 14 } 15 }
該類主要定義了產品的共有屬性和方法,用於子類繼承和實現。
- 其次定義每個產品的具體實現子類。
1 public class AmericanCoffee : Coffee 2 { 3 public override void GetName() 4 { 5 Console.WriteLine("我是一杯美式咖啡。"); 6 } 7 } 8 9 public class LatterCoffe: Coffee 10 { 11 public override void GetName() 12 { 13 Console.WriteLine("我是一杯拿鐵咖啡。"); 14 } 15 }
該類實現並繼承自抽象類,如需增加產品可直接建立新的子類並繼承自抽象類即可。
- 然後定義核心類,即工廠類。
1 public class CoffeeFactory 2 { 3 public CoffeeFactory() 4 { 5 } 6 7 /// <summary> 8 /// 簡單工廠中必須要有一個方法來根據指定的邏輯建立例項 9 /// </summary> 10 /// <param name="fruitType"></param> 11 /// <returns></returns> 12 public static Coffee OrderCoffe(CoffeeEnum coffeeEnum) 13 { 14 switch (coffeeEnum) 15 { 16 case CoffeeEnum.AmericanCoffee: 17 return new AmericanCoffee(); 18 case CoffeeEnum.LatterCoffe: 19 return new LatterCoffe(); 20 } 21 return null; 22 } 23 24 public enum CoffeeEnum 25 { 26 AmericanCoffee, 27 LatterCoffe 28 } 29 }
該類透過建立了一個列舉型別引數來選擇需要建立的產品例項。
- 最後客戶端呼叫。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //透過CoffeeFactory產品工廠建立了AmericanCoffee產品例項 6 Coffee coffee = CoffeeFactory.OrderCoffe(CoffeeFactory.CoffeeEnum.AmericanCoffee); 7 coffee.GetName(); 8 9 //透過CoffeeFactory產品工廠建立了LatterCoffe產品例項 10 coffee = CoffeeFactory.OrderCoffe(CoffeeFactory.CoffeeEnum.LatterCoffe); 11 coffee.GetName(); 12 coffee.AddSugar(); 13 } 14 }
根據客戶端的選擇條件來動態的例項化相關的類,
對於客戶端來說,其去除了與具體產品之間的依賴。
簡單工廠模式的缺點主要就是違背了開-閉原則,在上面的 Demo 中,如果我要再增加一種產品。
那麼,首先是定義一個新產品子類,讓其繼承自抽象類,然後呢,您還必須修改工廠類。
所以進而改進形成了工廠方法模式。
(二)工廠方法基礎介紹:
這是一種更高階的工廠模式,它透過抽象介面或基類中的工廠方法來建立物件。
具體實現由子類負責,因此更加靈活。這種設計方式有利於實現開閉原則,即對擴充套件開放,對修改封閉。
簡單工廠把全部的事情,在一個地方(類)全部處理完,而工廠方法卻不同,
定義一個用於建立物件的介面,讓子類決定例項化哪個產品類物件。工廠方法使一個產品類的例項化延遲到其工廠的子類。
這樣一來,擴充套件產品種類就不必修改工廠函式了,核心類就變成抽象類,工廠方法模式將生成具體產品的任務分發給具體的產品工廠。
也就是相當於工廠總部不生產產品了,交給下轄分工廠進行生產。
要增加產品類時也要相應地增加工廠類,不需要修改工廠類的程式碼了,這樣就解決了簡單工廠模式的缺點。
工廠方法模式是簡單工廠模式的進一步抽象。由於使用了多型性,工廠方法模式保持了簡單工廠模式的優點,而且克服了它的缺點。
工廠方法模式的主要角色:
抽象工廠:在抽象工廠類中宣告瞭工廠方法,用於返回一個產品。提供了建立產品的介面,呼叫者透過它訪問具體工廠的工廠方法來建立產品。
具體產品工廠:它是抽象工廠類的子類,實現了在抽象工廠中宣告的工廠方法,完成具體產品的建立。並可由客戶端呼叫,返回一個具體產品類的例項。
抽象產品:它是定義產品的介面,定義了產品的規範,描述了產品的主要特性和功能,是工廠方法模式所建立物件的公共父類。
具體產品:它實現了抽象產品介面,某種型別的具體產品由專門的具體工廠建立,具體工廠和具體產品之間一一對應。
缺點:每增加一個產品就要增加一個具體產品類和一個對應的具體工廠類,這增加了系統的複雜度。
工廠方法建立方式:
- 抽象產品類:
1 /// <summary> 2 /// 該類是產品的父類即抽象產品,定義所有子類的共有屬性和方法 3 /// </summary> 4 public abstract class Coffee 5 { 6 /// <summary> 7 /// 方便演示,只定義兩個代表性方法。 8 /// </summary> 9 public abstract void GetName(); 10 11 public void AddSugar() 12 { 13 Console.WriteLine("加糖"); 14 } 15 }
- 具體產品類:
1 public class AmericanCoffee : Coffee 2 { 3 public override void GetName() 4 { 5 Console.WriteLine("我是一杯美式咖啡。"); 6 } 7 } 8 9 public class LatterCoffe: Coffee 10 { 11 public override void GetName() 12 { 13 Console.WriteLine("我是一杯拿鐵咖啡。"); 14 } 15 }
- 抽象工廠:
1 /// <summary> 2 /// 抽象工廠 3 /// </summary> 4 public abstract class CoffeeFactory 5 { 6 public abstract Coffee GetCoffee(); 7 }
- 具體產品工廠:
1 /// <summary> 2 /// 美式咖啡工廠 3 /// </summary> 4 public class AmericanFactory:CoffeeFactory 5 { 6 public override Coffee GetCoffee() 7 { 8 return new AmericanCoffee(); 9 } 10 } 11 12 /// <summary> 13 /// 拿鐵咖啡工廠 14 /// </summary> 15 public class LatterFactory : CoffeeFactory 16 { 17 public override Coffee GetCoffee() 18 { 19 return new LatterCoffe(); 20 } 21 }
- 客戶端呼叫:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //首先建立一個美式咖啡工廠,只負責生產美式咖啡產品 6 CoffeeFactory coffeeFactory = new AmericanFactory(); 7 //在美式咖啡工廠中生產一個美式咖啡產品 8 Coffee coffee = coffeeFactory.GetCoffee(); 9 coffee.GetName(); 10 11 //建立一個拿鐵咖啡工廠,只負責生產拿鐵咖啡產品 12 coffeeFactory = new LatterFactory(); 13 //在工廠中生產一個拿鐵咖啡產品 14 coffee = coffeeFactory.GetCoffee(); 15 coffee.GetName(); 16 //咖啡中加糖 17 coffee.AddSugar(); 18 } 19 }
透過客戶端呼叫方式可以看出,不同產品的生產由原來的總工廠變為了各個分工廠去負責。
使用者只需要知道具體工廠的名稱就可得到所要的產品,無須知道產品的具體建立過程。
在系統增加新的產品時只需要新增具體產品類和對應的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則。
(三)抽象工廠基礎介紹:
上面兩種模式不管工廠怎麼拆分抽象,都只是針對一類產品,直接生成例項,這些工廠只生產同種類產品。
但是抽象工廠模式不同,抽象工廠模式並不直接生成例項, 而是用於對產品類簇的建立。
通俗點來講就是:簡單工廠和工廠方法模式的工作是生產產品,那麼抽象工廠模式的工作就是生產工廠的。
是一種為訪問類提供一個建立一組相關或相互依賴物件的介面,且訪問類無須指定所要產品的具體類就能得到同族的不同等級的產品的模式結構。
抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產一個等級的產品,而抽象工廠模式可生產多個等級的產品。
抽象工廠的最大好處在於交換產品系列非常方便,只需要改變具體工廠即可使用不同的產品配置。
抽象工廠模式的主要角色:
抽象工廠:在抽象工廠類中宣告瞭多個工廠方法,用於返回多個產品。提供了建立產品的介面,它包含多個建立產品的方法,可以建立多個不同等級的產品。
具體產品工廠:它是抽象工廠類的子類,實現了在抽象工廠中宣告的多個工廠方法,完成多個具體產品的建立。
抽象產品:它是定義一個產品的介面,定義了一個產品的規範,描述了一個產品的主要特性和功能。抽象工廠模式有多個抽象產品。
具體產品:實現了抽象產品角色所定義的介面,由具體工廠來建立,它同具體工廠之間是多對一的關係。
總的來說工廠方法模式一個工廠只生產一個產品,抽象工廠模式一個工廠生產多個產品,形成一個產品套餐,而多個工廠組成套餐系列。
抽象工廠建立方式:
- 抽象產品類,有多少個不同產品就建立多少個抽象產品類。
1 /// <summary> 2 /// 咖啡產品抽象類 3 /// </summary> 4 public abstract class Coffee 5 { 6 /// <summary> 7 /// 方便演示,只定義兩個代表性方法。 8 /// </summary> 9 public abstract void GetName(); 10 11 public void AddSugar() 12 { 13 Console.WriteLine("加糖"); 14 } 15 } 16 17 /// <summary> 18 /// 甜點產品抽象類 19 /// </summary> 20 public abstract class Dessert 21 { 22 public abstract void GetName(); 23 }
例項中建立了兩種產品,即咖啡和甜品。
- 具體產品類,不同產品繼承不同抽象類。
1 public class AmericanCoffee : Coffee 2 { 3 public override void GetName() 4 { 5 Console.WriteLine("我是一杯美式咖啡。"); 6 } 7 } 8 9 public class LatterCoffe: Coffee 10 { 11 public override void GetName() 12 { 13 Console.WriteLine("我是一杯拿鐵咖啡。"); 14 } 15 } 16 17 public class MatchaMousse: Dessert 18 { 19 public override void GetName() 20 { 21 Console.WriteLine("我是一塊抹茶慕斯。"); 22 } 23 } 24 25 public class Tiramisu: Dessert 26 { 27 public override void GetName() 28 { 29 Console.WriteLine("我是一塊提拉米蘇。"); 30 } 31 }
例項中定義了兩種咖啡和兩種甜點,咖啡為一個產品等級,甜點是另外一個產品等級。
- 抽象工廠類,有多少個系列就可以建立多少個抽象工廠類。本例項只建立了一個風味系列的工廠。
1 /// <summary> 2 /// 風味工廠 3 /// </summary> 4 public abstract class RelishFactory 5 { 6 //生產一杯咖啡 7 public abstract Coffee GetCoffee(); 8 //生產一塊甜點 9 public abstract Dessert GetDessert(); 10 }
例項中定義了一個系列的工廠,如果新增一個不同產品等級的奶茶,那就可以在風味工廠中生產一杯奶茶。同一種口味繫結為一個系列即一個抽象工廠。
- 具體工廠類,同一系列可以建立多個具體的工廠,負責同一系列下的不同產品出的建立。本例項建立了風味系列下的不同風味工廠的建立。
1 /// <summary> 2 /// 美式風味工廠 3 /// </summary> 4 public class AmericanRelishFactory : RelishFactory 5 { 6 public override Coffee GetCoffee() 7 { 8 return new AmericanCoffee(); 9 } 10 11 public override Dessert GetDessert() 12 { 13 return new MatchaMousse(); 14 } 15 } 16 17 /// <summary> 18 /// 義大利風味工廠 19 /// </summary> 20 public class ItalyRelishFactory : RelishFactory 21 { 22 public override Coffee GetCoffee() 23 { 24 return new LatterCoffe(); 25 } 26 27 public override Dessert GetDessert() 28 { 29 return new Tiramisu(); 30 } 31 }
例項中建立了兩種不同口味的工廠,選擇對應口味的工廠,可以生產出對應口味的不同產品。
比如選擇了美式口味工廠,該工廠可以生產出美式咖啡和抹茶慕斯。
實際上是該工廠將這兩個不同等級的產品進行繫結,形成了一個產品族。
- 客戶端呼叫:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //首先建立一種口味工廠 6 RelishFactory relishFactory = new AmericanRelishFactory(); 7 //然後對應口味工廠中生產出對應口味的不同產品。 8 Coffee coffee = relishFactory.GetCoffee(); 9 coffee.GetName(); 10 Dessert dessert = relishFactory.GetDessert(); 11 dessert.GetName(); 12 13 Console.WriteLine("換一種口味"); 14 relishFactory = new ItalyRelishFactory(); 15 coffee = relishFactory.GetCoffee(); 16 coffee.GetName(); 17 dessert = relishFactory.GetDessert(); 18 dessert.GetName(); 19 } 20 }
例項中可以看出建立了一個美式口味工廠,
該工廠就可以生產出符合該口味的不同產品。
其本質就是將相同口味的不同產品繫結成一個產品族,形成一個產品族工廠。
如果有多個產品族,那就建立多個產品族工廠就可以了。優點:當一個產品族中的多個物件被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的物件。缺點:當產品族中需要增加一個新的產品時,所有的工廠類都需要進行修改。
總結:
簡單工廠把全部的事情,在一個地方(類)全部處理完,
而工廠方法卻不同,
其是透過建立一個框架,
然後讓子類決定要如何實現。
而抽象工廠則是定義一個負責建立一組產品(也就是一個產品族)的介面,
抽象工廠的最大好處在於交換產品系列非常方便。
上述簡單工廠模式和工廠方法模式都是直接生成例項,但是抽象工廠模式不同,抽象工廠模式並不直接生成例項, 而是用於對產品類族的建立。
通俗點來講就是:簡單工廠和工廠方法模式的工作是生產產品,那麼抽象工廠模式的工作就是生產工廠的(產品類族)。
從上面可看到,簡單工廠的優點就是我們只要傳遞正確的引數,就能獲得所需的物件,而不需要關心其建立的具體細節。
工廠方法的優點就是讓其子類決定具體實現,如日誌記錄器:記錄可能記錄到本地硬碟、系統事件、遠端伺服器等。
抽象工廠模式一般用於嚴格要求以物件導向思想進行開發的超大型專案中。