工廠模式
首先,簡單工廠模式不屬於23中涉及模式,簡單工廠一般分為:普通簡單工廠、多方法簡單工廠、靜態方法簡單工廠。
A、簡單工廠模式
簡單工廠模式模式分為三種:
A1、普通
就是建立一個工廠類,對實現了同一介面的一些類進行例項的建立。首先看下關係圖:
[圖片上傳失敗...(image-13f411-1537173544176)]
舉例如下:(我們舉一個傳送郵件和簡訊的例子)
首先,建立二者的共同介面:
public interface Sender { public void Send(); }
其次,建立實現類:
public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mailsender!"); } }
public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } }
最後,建工廠類:
public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("請輸入正確的型別!"); return null; } } }
我們來測試下:
public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce("sms"); sender.Send(); } }
輸出:this is sms sender!
A2、多個方法
是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字串出錯,則不能正確建立物件,而多個工廠方法模式是提供多個工廠方法,分別建立物件。關係圖:
[圖片上傳失敗...(image-d4ea0d-1537173544176)]
將上面的程式碼做下修改,改動下SendFactory類就行,如下:
public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } }
測試類如下:
public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.Send(); } }
輸出:this is mailsender!
A3、多個靜態方法
將上面的多個工廠方法模式裡的方法置為靜態的,不需要建立例項,直接呼叫即可。
public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } }
public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.Send(); } }
輸出:this is mailsender!
總體來說,工廠模式適合:凡是出現了大量的產品需要建立,並且具有共同的介面時,可以通過工廠方法模式進行建立。在以上的三種模式中,第一種如果傳入的字串有誤,不能正確建立物件,第三種相對於第二種,不需要例項化工廠類,所以,大多數情況下,我們會選用第三種——靜態工廠方法模式。
B、工廠方法模式(Factory Method)
簡單工廠模式有一個問題就是,類的建立依賴工廠類,也就是說,如果想要拓展程式,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到工廠方法模式,建立一個工廠介面和建立多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的程式碼。
[圖片上傳失敗...(image-8c8dfb-1537173544176)]
public interface Sender { public void Send(); }
兩個實現類:
public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mailsender!"); } }
public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } }
在提供一個介面:
public interface Provider { public Sender produce(); }
兩個工廠類:
public class SendMailFactory implements Provider { @Override public Sender produce(){ return new MailSender(); } }
public class SendSmsFactory implements Provider{ @Override public Sender produce() { return new SmsSender(); } }
測試類:
public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } }
其實這個模式的好處就是,如果你現在想增加一個功能:發及時資訊,則只需做一個實現類,實現Sender介面,同時做一個工廠類,實現Provider介面,就OK了,無需去改動現成的程式碼。這樣做,拓展性較好!
C、抽象工廠模式
假設,時代進步了,通過郵件傳送語音了,通過簡訊也可傳送語音了
定義一個介面:
public interface Caller { public void call(); }
兩個實現類:
public class EmailCaller implements Caller { @Override public void call() { System.out.println("this is mailcaller!"); } }
public class SmsCaller implements Caller{ @Override public void call() { System.out.println("this is smscaller!"); } }
在提供一個介面:
public interface Provider { Sender produceSender(); Caller produceCaller(); }
兩個工廠類:
public class EmailFactory implements Provider{ @Override public Sender produceSender() { return new MailSender(); } @Override public Caller produceCaller() { return new EmailCaller(); } }
public class SmsFactory implements Provider { @Override public Sender produceSender() { return new SmsSender(); } @Override public Caller produceCaller() { return new SmsCaller(); } }
測試類:
public class Test { public static void main(String[] args) { Provider provider = new SmsFactory(); Sender sender = provider.produceSender(); Caller caller = provider.produceCaller(); sender.Send(); caller.call(); } }
只有一個Send的封裝類和Send操作類時,我們只用到了工廠方法模式,而且也只需要使用到工廠方法模式。但是顯然現在我們的功能已經不止一個Send了,而 Send 和 call 又是兩大不同的分類,所以解決這種涉及到多個產品系列的問題,就需要使用到專門解決這種問題的模式:抽象工廠模式。這時候再回過頭去看DP對抽象工廠模式的定義就不難理解了。
所以抽象工廠與工廠方法模式的區別在於:抽象工廠是可以生產多個產品的,例如 SmsFactory 裡可以生產 produceSender 以及 produceCaller 兩個產品,而這兩個產品又是屬於一個系列的,因為它們都是屬於Sms的功能。而工廠方法模式則只能生產一個產品,例如之前的 SendSmsFactory 裡就只可以生產一個 Sender 產品。
示意圖:

image
總結:
工廠方法模式和抽象工廠模式不好分清楚,他們的區別如下:
工廠方法模式:
一個抽象產品類,可以派生出多個具體產品類。
一個抽象工廠類,可以派生出多個具體工廠類。
每個具體工廠類只能建立一個具體產品類的例項。
抽象工廠模式:
多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。
一個抽象工廠類,可以派生出多個具體工廠類。
每個具體工廠類可以建立多個具體產品類的例項,也就是建立的是一個產品線下的多個產品。
區別:
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。
工廠方法模式的具體工廠類只能建立一個具體產品類的例項,而抽象工廠模式可以建立多個。
工廠方法建立 "一種" 產品,他的著重點在於"怎麼建立",也就是說如果你開發,你的大量程式碼很可能圍繞著這種產品的構造,初始化這些細節上面。也因為如此,類似的產品之間有很多可以複用的特徵,所以會和模版方法相隨。
抽象工廠需要建立一些列產品,著重點在於"建立哪些"產品上,也就是說,如果你開發,你的主要任務是劃分不同差異的產品線,並且儘量保持每條產品線介面一致,從而可以從同一個抽象工廠繼承。
對於java來說,你能見到的大部分抽象工廠模式都是這樣的:
---它的裡面是一堆工廠方法,每個工廠方法返回某種型別的物件。
比如說工廠可以生產滑鼠和鍵盤。那麼抽象工廠的實現類(它的某個具體子類)的物件都可以生產滑鼠和鍵盤,但可能工廠A生產的是羅技的鍵盤和滑鼠,工廠B是微軟的。
這樣A和B就是工廠,對應於抽象工廠;
每個工廠生產的滑鼠和鍵盤就是產品,對應於工廠方法;
用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。但是用了抽象工廠模式,你只要換家工廠,就可以同時替換滑鼠和鍵盤一套。如果你要的產品有幾十個,當然用抽象工廠模式一次替換全部最方便(這個工廠會替你用相應的工廠方法)
所以說抽象工廠就像工廠,而工廠方法則像是工廠的一種產品生產線