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