设计模式之工厂模式(Factory)(3)
? ? ? ? 在面向對象編程中,最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象實例的。但是在一些情況下,new操作符直接生成對象會帶來一些問題。舉例來說,許多類型對象的創(chuàng)造需要一系列的步驟:你可能需要計算或取得對象的初始設置;選擇生成哪個子對象實例;或在生成你需要的對象之前必須先生成一些輔助功能的對象。 在這些情況新對象的建立就是一個 “過程”,不僅是一個操作,像一部大機器中的一個齒輪傳動。
動機
? ? ? ? 工廠模式主要是為創(chuàng)建對象提供過渡接口,以便將創(chuàng)建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。
分類
工廠模式可以分為三類:
1)簡單工廠模式(Simple Factory)
2)工廠方法模式(Factory Method)
3)抽象工廠模式(Abstract Factory)
這三種模式從上到下逐步抽象,并且更具一般性。
區(qū)別
1)工廠方法模式:
- 一個抽象產品類,可以派生出多個具體產品類。
- 一個抽象工廠類,可以派生出多個具體工廠類。
- 每個具體工廠類只能創(chuàng)建一個具體產品類的實例。
2)抽象工廠模式:
- 多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。
- 一個抽象工廠類,可以派生出多個具體工廠類。
- 每個具體工廠類可以創(chuàng)建多個具體產品類的實例。
區(qū)別:
- 工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。
- 工廠方法模式的具體工廠類只能創(chuàng)建一個具體產品類的實例,而抽象工廠模式可以創(chuàng)建多個。
下面具體介紹下這三種工廠模式。
一、 簡單工廠模式
簡介
? ? ? ? 簡單工廠模式是屬于創(chuàng)建型模式,又叫做靜態(tài)工廠方法(Static Factory Method)模式,但不屬于23種GOF設計模式之一。簡單工廠模式是由一個工廠對象決定創(chuàng)建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現。
延伸
? ? ? ? 試想一下,當我們在codeing的時候,在A類里面只要NEW了一個B類的對象,那么A類就會從某種程度上依賴B類。如果在后期需求發(fā)生變化或者是維護的時候,需要修改B類的時候,我們就需要打開源代碼修改所有與這個類有關的類了,做過重構的朋友都知道,這樣的事情雖然無法完全避免,但確實是一件讓人心碎的事情。
組成
優(yōu)點
? ? ? ? ?簡單工廠模式能夠根據外界給定的信息,決定究竟應該創(chuàng)建哪個具體類的對象。明確區(qū)分了各自的職責和權力,有利于整個軟件體系結構的優(yōu)化。
缺點
? ? ? ? 很明顯工廠類集中了所有實例的創(chuàng)建邏輯,容易違反GRASPR的高內聚的責任分配原則。
模擬場景
? ? ? ? 聯(lián)想電腦旗下有很多產品,其中有一類新產品叫ThinkPad,該產品有幾個版本,其中兩個叫ThinkPadS1和ThinkPadS2,用戶不用去創(chuàng)建ThinkPad。因為客戶有一個工廠來幫他創(chuàng)建ThinkPad,想要什么版本,這個工廠就可以建。比如想要S1版本,工廠就創(chuàng)建這個版本的ThinkPad。即工廠可以創(chuàng)建產品。
類圖
?
圖1 簡單工廠模式實例類圖
實例
Java
//產品類 abstract class ThinkPad{public ThinkPad() {//Console.WriteLine("This is ThinkPad!"); } } class ThinkPadS1 extends ThinkPad{public ThinkPadS1() {System.out.println("This is ThinkPadS1!");} }class ThinkPadS2 extends ThinkPad{public ThinkPadS2() {System.out.println("This is ThinkPadS2!");} } //工廠類 package FactoryDemo; public class SimpleFactory {public ThinkPad GetTypeofThinkPad(int type){switch (type){case 1: return new ThinkPadS1();case 2: return new ThinkPadS2();default: break;}return null;} } package FactoryDemo; //客戶類 public class Client {public static void main(String[] args) {// 簡單工廠模式SimpleFactory factory = new SimpleFactory();ThinkPad tps1=factory.GetTypeofThinkPad(1);ThinkPad tps2 = factory.GetTypeofThinkPad(2);} } View CodeC#
//產品類public abstract class ThinkPad{public ThinkPad(){//Console.WriteLine("This is ThinkPad!"); }}public class ThinkPadS1 : ThinkPad{public ThinkPadS1(){Console.WriteLine("This is ThinkPadS1!");}}public class ThinkPadS2 : ThinkPad{public ThinkPadS2(){Console.WriteLine("This is ThinkPadS2!");}}//工廠類public class SimpleFactory{public ThinkPad GetTypeofThinkPad(string type){switch (type){case "S1": return new ThinkPadS1();case "S2": return new ThinkPadS2();default: break;}return null;}}//客戶類class Program{static void Main(string[] args){// /*簡單工廠模式SimpleFactory factory = new SimpleFactory();ThinkPad tps1=factory.GetTypeofThinkPad("S1");ThinkPad tps2 = factory.GetTypeofThinkPad("S2");}} View Code? ? ? ? 下面我們從開閉原則(對擴展開放;對修改封閉)上來分析下簡單工廠模式。當客戶不再滿足現有的版本的時候,想要一種性能更好ThinkPad,只要這種ThinkPad符合抽象產品制定的合同,那么只要通知工廠類知道就可以被客戶使用了。所以對產品部分來說,它是符合開閉原則的;但是工廠部分好像不太理想,因為每增加一種新版本電腦,都要在工廠類中增加相應的創(chuàng)建業(yè)務邏輯(createBMW($type)方法需要新增case),這顯然是違背開閉原則的。可想而知對于新產品的加入,工廠類是很被動的。對于這樣的工廠類,我們稱它為全能類或者上帝類。
? ? ? ? 我們舉的例子是最簡單的情況,而在實際應用中,很可能產品是一個多層次的樹狀結構。由于簡單工廠模式中只有一個工廠類來對應這些產品,所以這可能會把我們的上帝累壞了,也累壞了我們這些程序員。
? ? ? ? 于是工廠方法模式作為救世主出現了。 工廠類定義成了接口,而每新增的車種類型,就增加該車種類型對應工廠類的實現,這樣工廠的設計就可以擴展了,而不必去修改原來的代碼。
二、工廠方法模式
簡介
? ? ? ? 工廠方法模式Factory Method,又稱多態(tài)性工廠模式。在工廠方法模式中,核心的工廠類不再負責所有的產品的創(chuàng)建,而是將具體創(chuàng)建的工作交給子類去做。該核心類成為一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪一個產品類應當被實例化這種細節(jié)。
定義
? ? ? ? 工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先完全實現‘開-閉原則’,實現了可擴展。其次更復雜的層次結構,可以應用于產品結果復雜的場合。
組成
1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
2)具體工廠角色:它含有和具體業(yè)務邏輯有關的代碼。由應用程序調用以創(chuàng)建對應的具體產品的對象。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在java中一般有抽象類或者接口來實現。
4)具體產品角色:具體工廠角色所創(chuàng)建的對象就是此角色的實例。在java中由具體的類來實現。
使用條件
1)當客戶程序不需要知道要使用對象的創(chuàng)建過程。
2)客戶程序使用的對象存在變動的可能,或者根本就不知道使用哪一個具體的對象。
優(yōu)點
- 子類提供掛鉤。基類為工廠方法提供缺省實現,子類可以重寫新的實現,也可以繼承父類的實現。加一層間接性,增加了靈活性
- ?屏蔽產品類。產品類的實現如何變化,調用者都不需要關心,只需關心產品的接口,只要接口保持不變,系統(tǒng)中的上層模塊就不會發(fā)生變化。
- ?典型的解耦框架。高層模塊只需要知道產品的抽象類,其他的實現類都不需要關心,符合迪米特法則,符合依賴倒置原則,符合里氏替換原則。
- ?多態(tài)性:客戶代碼可以做到與特定應用無關,適用于任何實體類。
缺點
? ? ? ? 需要Creator和相應的子類作為factory method的載體,如果應用模型確實需要creator和子類存在,則很好;否則的話,需要增加一個類層次。
模擬場景
? ? ? ? 工廠方法模式使用繼承自抽象工廠角色的多個子類來代替簡單工廠模式中的“上帝類”。正如上面所說,這樣便分擔了對象承受的壓力;而且這樣使得結構變得靈活起來——當有新的產品產生時,只要按照抽象產品角色、抽象工廠角色提供的合同來生成,那么就可以被客戶使用,而不必去修改任何已有的代碼??梢钥闯龉S角色的結構也是符合開閉原則的。
類圖
圖2 工廠方法模式實例類圖
實例
Java
//產品類 abstract class ThinkPad{public ThinkPad() {//Console.WriteLine("This is ThinkPad!"); } } class ThinkPadS1 extends ThinkPad{public ThinkPadS1() {System.out.println("This is ThinkPadS1!");} }class ThinkPadS2 extends ThinkPad{public ThinkPadS2() {System.out.println("This is ThinkPadS2!");} } package FactoryDemo; //工廠類 interface FactoryMethod {ThinkPad GetTypeofThinkPad(); }class FactoryThinkPadS1 implements FactoryMethod {public ThinkPad GetTypeofThinkPad() {return new ThinkPadS1();} } class FactoryThinkPadS2 implements FactoryMethod {public ThinkPad GetTypeofThinkPad() {return new ThinkPadS2();} } package FactoryDemo; //客戶類 public class Client {public static void main(String[] args) { // 工廠方法模式FactoryThinkPadS1 factory_ThinkPadS1 = new FactoryThinkPadS1();ThinkPad f_tps1 = factory_ThinkPadS1.GetTypeofThinkPad();FactoryThinkPadS2 factory_ThinkPadS2 = new FactoryThinkPadS2();ThinkPad f_tps2 = factory_ThinkPadS2.GetTypeofThinkPad();} } View CodeC#
//產品類 public abstract class ThinkPad{public ThinkPad(){//Console.WriteLine("This is ThinkPad!"); }}public class ThinkPadS1 : ThinkPad{public ThinkPadS1(){Console.WriteLine("This is ThinkPadS1!");}}public class ThinkPadS2 : ThinkPad{public ThinkPadS2(){Console.WriteLine("This is ThinkPadS2!");}} //工廠類public interface FactoryMethod{ThinkPad GetTypeofThinkPad(); }public class FactoryThinkPadS1:FactoryMethod{public ThinkPad GetTypeofThinkPad(){return new ThinkPadS1();}}public class FactoryThinkPadS2 : FactoryMethod{public ThinkPad GetTypeofThinkPad(){return new ThinkPadS2();}} //客戶類: class Program{static void Main(string[] args){// 工廠方法模式FactoryThinkPadS1 factory_ThinkPadS1 = new FactoryThinkPadS1();ThinkPad f_tps1 = factory_ThinkPadS1.GetTypeofThinkPad();FactoryThinkPadS2 factory_ThinkPadS2 = new FactoryThinkPadS2();ThinkPad f_tps2 = factory_ThinkPadS2.GetTypeofThinkPad();Console.ReadLine();}} View Code可以看出工廠方法的加入,使得對象的數量成倍增長。當產品種類非常多時,會出現大量的與之對應的工廠對象,這不是我們所希望的。因為如果不能避免這種情 況,可以考慮使用簡單工廠模式與工廠方法模式相結合的方式來減少工廠類:即對于產品樹上類似的種類(一般是樹的葉子中互為兄弟的)使用簡單工廠模式來實現。
三、抽象工廠模式
簡介
抽象工廠模式是所有形態(tài)的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產品的具體的情況下,創(chuàng)建多個產品族中的產品對象。根據里氏替換原則,任何接受父類型的地方,都應當能夠接受子類型。因此,實際上系統(tǒng)所需要的,僅僅是類型與這些抽象產品角色相同的一些實例,而不是這些抽象產品的實例。換言之,也就是這些抽象產品的具體子類的實例。工廠類負責創(chuàng)建抽象產品的具體子類的實例。
定義
為創(chuàng)建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。
組成
1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
2)具體工廠角色:它含有和具體業(yè)務邏輯有關的代碼。由應用程序調用以創(chuàng)建對應的具體產品的對象。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。
4)具體產品角色:具體工廠角色所創(chuàng)建的對象就是此角色的實例。
使用條件
1)系統(tǒng)中有多個產品族,而系統(tǒng)一次只可能消費其中一族產品。
2)同屬于同一個產品族的產品一起使用。
優(yōu)點
- ?抽象工廠模式隔離了具體類的生產,使得客戶并不需要知道什么被創(chuàng)建。
- ?當一個產品族中的多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的對象。
- ?增加新的具體工廠和產品族很方便,無須修改已有系統(tǒng),符合“開閉原則”。
缺點
? ? ? 增加新的產品等級結構很復雜,需要修改抽象工廠和所有的具體工廠類,對“開閉原則”的支持呈現傾斜性。
模擬場景
? ? ? ? 隨著客戶的要求越來越高,他們需要知道每個版本的顯卡和主板型號,ThinkPad需要配置顯卡和主板,這個工廠開始生產顯卡和主板。這時候工廠有二個系列的產品:顯卡和主板。而每個版本的ThinkPad需要配置不同的顯卡和主板。這時候分別使用一個顯卡工廠和一個主板工廠都不能滿足我們的需求,我們必須確認電腦跟配件的對應關系。因此把電腦工廠跟配件工廠聯(lián)系在一起。因此出現了抽象工廠模式。
類圖
圖3 抽象工廠模式實例類圖
實例
Java
//產品類 abstract class Motherboard{ } class MotherboardA extends Motherboard{public MotherboardA() {System.out.println("This is MotherboardA");} } class MotherboardB extends Motherboard{public MotherboardB() {System.out.println("This is MotherboardB");} } class VideoCard{ }class VideoCardA extends VideoCard{public VideoCardA() {System.out.println("This is VideoCardA");} } class VideoCardB extends VideoCard{public VideoCardB() {System.out.println("This is VideoCardB");} } package FactoryDemo; //工廠類 interface AbstractFactory{Motherboard GetMotherboard();VideoCard GetVideoCard(); }class AbstractFactoryThinkPadS1 implements AbstractFactory {public Motherboard GetMotherboard() {return new MotherboardA();}public VideoCard GetVideoCard() {return new VideoCardA();} } class AbstractFactoryThinkPadS2 implements AbstractFactory{public Motherboard GetMotherboard(){return new MotherboardB();}public VideoCard GetVideoCard(){return new VideoCardB();} } package FactoryDemo; //客戶類 public class Client {public static void main(String[] args) {// 抽象工廠模式AbstractFactoryThinkPadS1 aFactory_S1 = new AbstractFactoryThinkPadS1();aFactory_S1.GetMotherboard();aFactory_S1.GetVideoCard();AbstractFactoryThinkPadS2 aFactory_S2 = new AbstractFactoryThinkPadS2();aFactory_S2.GetMotherboard();aFactory_S2.GetVideoCard();} } View CodeC#
//產品類public class Motherboard{ }public class MotherboardA : Motherboard{public MotherboardA(){Console.WriteLine("This is MotherboardA");}}public class MotherboardB : Motherboard{public MotherboardB(){Console.WriteLine("This is MotherboardB");}}public class VideoCard{ }public class VideoCardA : VideoCard{public VideoCardA(){Console.WriteLine("This is VideoCardA");}}public class VideoCardB : VideoCard{public VideoCardB(){Console.WriteLine("This is VideoCardB");}} //工廠類 public interface AbstractFactory{Motherboard GetMotherboard();VideoCard GetVideoCard();}public class AbstractFactoryThinkPadS1 : AbstractFactory{public Motherboard GetMotherboard(){return new MotherboardA();}public VideoCard GetVideoCard() {return new VideoCardA();}}public class AbstractFactoryThinkPadS2 : AbstractFactory{public Motherboard GetMotherboard(){return new MotherboardB();}public VideoCard GetVideoCard(){return new VideoCardB();}} class Program{static void Main(string[] args){//抽象工廠模式AbstractFactoryThinkPadS1 aFactoryS1 = new AbstractFactoryThinkPadS1();aFactoryS1.GetMotherboard();aFactoryS1.GetVideoCard();AbstractFactoryThinkPadS2 aFactoryS2 = new AbstractFactoryThinkPadS2();aFactoryS2.GetMotherboard();aFactoryS2.GetVideoCard();Console.ReadLine();}} View Code四、總結
? ? ? ? 首先,我們需要明確使用工廠模式的目的是降低耦合度,所以,當遇到存在分類問題并且類別還會變動的情況下,像創(chuàng)建產品這樣,可以考慮是否能有工廠模式。簡單工廠模式能夠根據外界給定的信息,決定究竟應該創(chuàng)建哪個具體類的對象,明確區(qū)分了各自的職責和權力,有利于整個軟件體系結構的優(yōu)化,但擴展性不高,耦合度高;當客戶程序不需要知道要使用對象的創(chuàng)建過程,或者客戶程序使用的對象存在變動的可能,或者根本就不知道使用哪一個具體的對象,可以考慮用工廠方法模式。當系統(tǒng)中有多個產品族,而系統(tǒng)一次只可能消費其中一族產品,或者同屬于同一個產品族的產品一起使用,可以考慮用抽象工廠模式。
轉載于:https://www.cnblogs.com/CIreland/p/9385870.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的设计模式之工厂模式(Factory)(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mac 安装Fiddler 抓包工具
- 下一篇: c++的继承