java設計模式中的工廠模式
工廠模式的形態
工廠模式主要用一下幾種形態:
1:簡單工廠(Simple Factory)。
2:工廠方法(Factory Method)。
3:抽象工廠(Abstract Factory)。
簡單工廠(Simple Factory)
又叫靜態工廠,是工廠模式三中狀態中結構最為簡單的。主要有一個靜態方法,用來接受引數,並根據引數來決定返回實現同一介面的不同類的例項。我們來看一個具體的例子:
假設一家工廠,幾生產洗衣機,有生產冰箱,還有空調等等..
我們先為所有產品定義一個共同的產品介面
Java程式碼
- public interface Product{}
public interface Product{}
接著我們讓這個工廠的所有產品都必須實現此介面
Java程式碼
- public class Washerimplements Product{
- public Washer(){
- System.out.println("洗衣機被製造了");
- }
- }
- public class Iceboximplements Product{
- public Icebox(){
- System.out.println("冰箱被製造了");
- }
- }
- public class AirConditionimplements Product{
- public
- System.out.println("空調被製造了");
- }
- }
public class Washer implements Product{ public Washer(){ System.out.println("洗衣機被製造了"); } } public class Icebox implements Product{ public Icebox(){ System.out.println("冰箱被製造了"); } } public class AirCondition implements Product{ public Icebox(){ System.out.println("空調被製造了"); } }
接下來我們來寫一個工廠類,有它來負責生產以上的產品
Java程式碼
- public class SimpleFactory {
- public static Product factory(String productName)throws Exception{
- if(productName.equals("Washer")){
- return new Washer();
- }else if(productName.equals("Icebox")){
- return new Icebox();
- }else if(productName.equals("AirCondition")){
- return new AirCondition();
- }else{
- throw new Exception("沒有該產品");
- }
- }
- }
public class SimpleFactory {
public static Product factory(String productName) throws Exception{
if(productName.equals("Washer")){
return new Washer();
}else if(productName.equals("Icebox")){
return new Icebox();
}else if(productName.equals("AirCondition")){
return new AirCondition();
}else{
throw new Exception("沒有該產品");
}
}
}
好了,有了這個工廠類,我們就可以開始下定單了,SimpleFactory將根據不同的定單類決定生產什麼產品。
Java程式碼
- public static void main(String[] args) {
- try {
- SimpleFactory.factory("Washer");
- SimpleFactory.factory("Icebox");
- SimpleFactory.factory("AirCondition");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
public static void main(String[] args) {
try {
SimpleFactory.factory("Washer");
SimpleFactory.factory("Icebox");
SimpleFactory.factory("AirCondition");
} catch (Exception e) {
e.printStackTrace();
}
}
由上面的程式碼可以看出,簡單工廠的核心就是一個SimpleFactory類,他擁有必要的邏輯判斷能力和所有產品的建立權利,我們只需要向把定單給他,就能得到我們想要的產品。這使用起來似乎非常方便。
但,實際上,這個SimpleFactory有很多的侷限。首先,我們每次想要增加一種新產品的時候,都必須修改SimpleFactory的原始碼。其次,當我們擁有很多很多產品的時候,而且產品之間又存在複雜的層次關係的時候,這個類必須擁有複雜的邏輯判斷能力,其程式碼量也將不斷地激增,這對以後的維護簡直就是恐怖兩個字...
還有就是,整個系統都嚴重依賴SimpleFactory類,只要SimpleFactory類一出問題,系統就進入不能工作的狀態,這也是最為致命的一點....
以上的不足將在工廠模式的另外兩種狀態中得到解決。
工廠方法(Factory Method)
上面的程式碼告訴我們,簡單工廠並不簡單,它是整個模式的核心,一旦他出了問題,整個模式都將受影響而不能工作,為了降低風險和為日後的維護、擴充套件做準備,我們需要對它進行重構,引入工廠方法。
工廠方法為工廠類定義了介面,用多型來削弱了工廠類的職能,以下是工廠介面的定義:
Java程式碼
- public interface Factory{
- public Product create();
- }
public interface Factory{
public Product create();
}
我們再來定義一個產品介面
Java程式碼
- public interface Product{}
public interface Product{}
一下是實現了產品介面的產品類
Java程式碼
- public class Washerimplements Product{
- public Washer(){
- System.out.println("洗衣機被製造了");
- }
- }
- public class Iceboximplements Product{
- public Icebox(){
- System.out.println("冰箱被製造了");
- }
- }
- public class AirConditionimplements Product{
- public Icebox(){
- System.out.println("空調被製造了");
- }
- }
public class Washer implements Product{
public Washer(){
System.out.println("洗衣機被製造了");
}
}
public class Icebox implements Product{
public Icebox(){
System.out.println("冰箱被製造了");
}
}
public class AirCondition implements Product{
public Icebox(){
System.out.println("空調被製造了");
}
}
接下來,就是工廠方法的核心部分,也就是具體建立產品物件的具體工廠類,
Java程式碼
- //建立洗衣機的工廠
- public class CreateWasherimplements Factory{
- public Product create(){
- return new Washer();
- }
- }
- //建立冰箱的工廠
- public class CreateIceboximplements Factory{
- public Product create(){
- return new Icebox();
- }
- }
- //建立空調的工廠
- public class CreateAirConditionimplements Factory{
- public Product create(){
- return new AirCondition();
- }
- }
//建立洗衣機的工廠
public class CreateWasher implements Factory{
public Product create(){
return new Washer();
}
}
//建立冰箱的工廠
public class CreateIcebox implements Factory{
public Product create(){
return new Icebox();
}
}
//建立空調的工廠
public class CreateAirCondition implements Factory{
public Product create(){
return new AirCondition();
}
}
從上面建立產品物件的程式碼可以看出,工廠方法和簡單工廠的主要區別是,簡單工廠是把建立產品的職能都放在一個類裡面,而工廠方法則把不同的產品放在實現了工廠介面的不同工廠類裡面,這樣就算其中一個工廠類出了問題,其他工廠類也能正常工作,互相不受影響,以後增加新產品,也只需要新增一個實現工廠介面工廠類,就能達到,不用修改已有的程式碼。但工廠方法也有他侷限的地方,那就是當面對的產品有複雜的等級結構的時候,例如,工廠除了生產家電外產品,還生產手機產品,這樣一來家電是手機就是兩大產品家族了,這兩大家族下面包含了數量眾多的產品,每個產品又有多個型號,這樣就形成了一個複雜的產品樹了。如果用工廠方法來設計這個產品家族系統,就必須為每個型號的產品建立一個對應的工廠類,當有數百種甚至上千種產品的時候,也必須要有對應的上百成千個工廠類,這就出現了傳說的類爆炸,對於以後的維護來說,簡直就是一場災難.....
抽象工廠(Factory Method)
抽象工廠:意的意圖在於建立一系列互相關聯或互相依賴的物件。<<Java設計模式>>
我自己覺得抽象工廠是在工廠方法的基礎上引進了分類管理的概念....
工廠方法用來建立一個產品,它沒有分類的概念,而抽象工廠則用於建立一系列產品,所以產品分類成了抽象工廠的重點,
我們繼續用上面的例子來說明:
工廠生產的所有產品都用都用大寫字母來標明它們的型號,比如冰箱,就有“冰箱-A",“冰箱-B",同樣,其他的產品也都是遵守這個編號規則,於是就有了一下產品家族樹
冰箱:
- 冰箱-A
- 冰箱-B
洗衣機:
- 洗衣機-A
- 洗衣機-B
我們可以為冰箱和洗衣機分別定義兩個產品介面,以對他們進行分類,
Java程式碼
- //洗衣機介面
- public interface Washer{
- }
- //冰箱介面
- public interface Icebox{
- }
//洗衣機介面
public interface Washer{
}
//冰箱介面
public interface Icebox{
}
接著,我們分別建立這兩個介面的具體產品
Java程式碼
- //洗衣機-A
- public class WasherAimplements Washer{
- public WasherA(){
- System.out.println("洗衣機-A被製造了");
- }
- }
- //洗衣機-B
- public class WasherBimplements Washer{
- public WasherB(){
- System.out.println("洗衣機-B被製造了");
- }
- }
- //冰箱-A
- public class IceboxAimplements Icebox{
- public IceboxA(){
- System.out.println("冰箱-A被製造了");
- }
- }
- //冰箱-B
- public class IceboxBimplements Icebox{
- public IceboxB(){
- System.out.println("冰箱-B被製造了");
- }
- }
//洗衣機-A
public class WasherA implements Washer{
public WasherA(){
System.out.println("洗衣機-A被製造了");
}
}
//洗衣機-B
public class WasherB implements Washer{
public WasherB(){
System.out.println("洗衣機-B被製造了");
}
}
//冰箱-A
public class IceboxA implements Icebox{
public IceboxA(){
System.out.println("冰箱-A被製造了");
}
}
//冰箱-B
public class IceboxB implements Icebox{
public IceboxB(){
System.out.println("冰箱-B被製造了");
}
}
到此,產品部分我們準備好了,接下來我們來處理工廠部分,我們先來定義工廠行為介面
Java程式碼
- public interface Factory{
- public Washer createWasher();
- public Icebox createIcebox();
- }
public interface Factory{
public Washer createWasher();
public Icebox createIcebox();
}
接下來我創造具體的工廠類,我們根據上面產品的介面,把型號A的產品分為一類,由一個工廠來管理,把型號為B的產品有另一個工廠管理,根據這個分類,我們可以實現如下的兩個具體工廠類
Java程式碼
- //建立型號為A的產品工廠
- public class FactoryAimplements Factory{
- //建立洗衣機-A
- public Washer createWasher(){
- return new WasherA();
- }
- //建立冰箱-A
- public Icebox createIcebox(){
- return new IceboxA();
- }
- }
- //建立型號為B的產品工廠
- public class FactoryBimplements Factory{
- //建立洗衣機-B
- public Washer createWasher(){
- return new WasherB();
- }
- //建立冰箱-B
- public Icebox createIcebox(){
- return new IceboxB();
- }
- }
//建立型號為A的產品工廠
public class FactoryA implements Factory{
//建立洗衣機-A
public Washer createWasher(){
return new WasherA();
}
//建立冰箱-A
public Icebox createIcebox(){
return new IceboxA();
}
}
//建立型號為B的產品工廠
public class FactoryB implements Factory{
//建立洗衣機-B
public Washer createWasher(){
return new WasherB();
}
//建立冰箱-B
public Icebox createIcebox(){
return new IceboxB();
}
}
這樣,我們的抽象工廠就完成了。有上面可以看出,在運用上我覺得工廠方法和抽象工廠,都有自己的應用場景,並沒有什麼優劣之分,但在應用抽象工廠之前,要先對建立的物件進行系統的分類,這點很重要,好的產品分類規則能為具體工廠類的選擇呼叫和以後的擴充套件提供清晰的思路.
angrfeng個人總結:
靜態工廠:工廠很原始,工廠有什麼,就只能製造什麼,有新產品進來,要重新設計工廠(修改原始碼),往廠裡新增新產品的型別,某產品有變更,也要修改工廠,導致一個最嚴重問題,某一條生成線(製作不同的產品線)炸了,就是工廠炸了,然後整個生成線都炸了,boom!!boom7炸了,難道整個三星的手機廠都炸了?這樣設計明顯弊端很大!
工廠方法:工廠相對先進,有一個總工廠,總工廠下有很多子工廠,各個子工廠工作明確,製造的產品分離開,有新產品進來,不用像靜態工廠一樣改造總廠的東西,只要新增一個子工廠即可,修改某產品的設計,也只要修改改產品的子工廠設計即可。某一子工廠出現問題,不會影響其他子工廠,boom7炸了,s6這些手機還是能繼續生產的。但是該模式也有一個弊端,就是隻能生產關係結構簡單的產品。例如,三星做手機,但是又想做做手機膜,然後因為某些原因,各個手機的型號,大小,螢幕不同的原因,要製造跟手機型號匹配的手機膜。問題來了,現在是不是要重新又製造一個手機膜工廠,又根據不同的型號建立一大堆不同型號的手機膜工廠?如果還有其他對應的配件要生產,是不是又要建立一個配件廠,又建立一代對不同手機型號的配件廠?這就出現了類爆炸了。手機螢幕和手機膜之類的子工廠之間沒有聯絡(不同型號手機的配件子工廠沒聯絡就算了,同一手機下的配件子工廠都沒有聯絡),這樣的工廠管理起來,不會很麻煩嗎?
抽象工廠:工廠更加先進,在設計一個產品時,將產品和相關產品的生產方式抽象出來,放進一個總工廠裡。當生產某一具體產品時,繼承總工廠的模式,建立子產品生產線和相關產品生產線。例如:三星手機總廠,生產手機要生產什麼?螢幕,cpu,電池,外殼,還有手機膜等等,這些都是手機必備的,但是又是不同手機有不同型號啊大小啊的。現在總工廠將這些抽取出來,以後建廠就按照這個模板來。要生產s5,就建一個s5的手機廠,手機廠下有多條負責不同配件的生產線(這些不同配件生產線也可以抽取出來建廠製造,或者叫富士康代工...),生產boom7也一樣。現在bonm7炸了,可以返廠,檢查boom7下的各個生產線究竟哪裡出錯,馬上修改解決!這樣就實現了各類子工廠之間隔離,子工廠裡各類生產線隔離,但是子工廠屬於總工廠,各類子工廠生產線屬於子工廠。每一個生產線之間關係簡單,每一個子工廠之間結構明瞭!
感覺我的想法跟原帖的抽象工廠和工廠方法兩個有點分歧,以上紅字是我個人的理解,若有不正確的地方歡迎留言指正。。。