設(shè)計模式之工廠模式
工廠模式:
當(dāng)創(chuàng)建邏輯比較復(fù)雜時,就可以考慮使用工廠模式,封裝對象的創(chuàng)建過程,將對象的創(chuàng)建和使用相分離。
工廠模式,屬于創(chuàng)建類型
實際代碼我放在了Github: https://github.com/liangtengyu/DesignPatterns-for-Java
應(yīng)用場景:
學(xué)習(xí)一個設(shè)計模式之前 我們先了解它的使用場景能夠幫我們更快的理解它, 相對于直接 new 來創(chuàng)建對象,用工廠模式來創(chuàng)建究竟有什么好處呢?
主要有兩種情況:
第一種情況是類似規(guī)則配置解析的例子,代碼中存在 if-else 分支判斷,動態(tài)的根據(jù)不同的類型創(chuàng)建不同的對象。針對這種情況,我們就可以考慮使用工廠模式,將這一大塊的 if-else 創(chuàng)建對象的代碼抽離出來,放到工廠類中。
還有一種情況是,盡管我們不需要根據(jù)不同的類型創(chuàng)建不同的對象,但是,單個對象本身的創(chuàng)建過程比較復(fù)雜,我們也可以考慮使用工廠模式。
好處:由于工廠模式是依靠抽象架構(gòu)的,它把實例化產(chǎn)品的任務(wù)交由實現(xiàn)類完成,擴展性比較好。也就是說,當(dāng)需要系統(tǒng)有比較好的擴展性時,可以考慮工廠模式,不同的產(chǎn)品用不同的實現(xiàn)工廠來組裝。通俗的講就是降低代碼改變對產(chǎn)品功能的影響.
實現(xiàn)方式:
簡單工廠(Simple Factory)
首先,我們來看,什么是簡單工廠模式。我們通過一個例子來解釋一下。
簡單工廠模式
public class Cocacola implements Cola {
public String getCola() {
return "可口可樂";
}
}
public class ColaFactory {
public static Cola getInstance(Integer colaType) {
if (1 == colaType) {
return new Cocacola();
} else if (2 == colaType) {
return new Pepsicola();
} else {
return new Fakecola();
}
}
}
public static void main(String[] args) {
String drink = ColaFactory.getInstance(1).drink();
System.out.println(drink);
}
//可口可樂
盡管簡單工廠模式的代碼實現(xiàn)中,有多處 if 分支判斷邏輯,違背開閉原則,但權(quán)衡擴展性和可讀性,這樣的代碼實現(xiàn)在大多數(shù)情況下是沒有問題的。
工廠方法(Factory Method)
工廠方法是簡單工廠的進一步的延伸,這樣說是因為簡單工廠違反了開閉原則,而此時工廠方法卻可以完美的解決這個問題!接下來看看它是怎么解決的吧!
對于規(guī)則配置文件解析這個應(yīng)用場景來說,工廠模式需要額外創(chuàng)建諸多 Factory 類,也會增加代碼的復(fù)雜性,而且,每個 Factory 類只是做簡單的 new 操作,功能非常單薄(只有一行代碼),也沒必要設(shè)計成獨立的類,所以,在這個應(yīng)用場景下,簡單工廠模式好用,比工廠方法模式更加合適
public interface ColaFactory {//工廠接口
Cola getCola();
}
public class CocaColaFactoryImpl implements ColaFactory {//實現(xiàn)可口可樂工廠
public Cola getCola() {
return new Cocacola();
}
}
public static void main(String[] args) {
//工廠方法需要一個可樂時,直接去對應(yīng)的工廠拿,而是不像簡單工廠那樣 都是從一個工廠中根據(jù)判斷來拿
//每一種可樂都對應(yīng)一個工廠
ColaFactory pepsiColaFactory = new PepsiColaFactoryImpl();
Cola cola = pepsiColaFactory.getCola();
cola.getCola();
}
什么時候該用工廠方法模式,而非簡單工廠模式呢?
之所以將某個代碼塊剝離出來,獨立為函數(shù)或者類,原因是這個代碼塊的邏輯過于復(fù)雜,剝離之后能讓代碼更加清晰,更加可讀、可維護。
但是,如果代碼塊本身并不復(fù)雜,就幾行代碼而已,我們完全沒必要將它拆分成單獨的函數(shù)或者類。基于這個設(shè)計思想,當(dāng)對象的創(chuàng)建邏輯比較復(fù)雜,不只是簡單的 new 一下就可以,而是要組合其他類對象,做各種初始化操作的時候,我們推薦使用工廠方法模式,將復(fù)雜的創(chuàng)建邏輯拆分到多個工廠類中,讓每個工廠類都不至于過于復(fù)雜。而使用簡單工廠模式,將所有的創(chuàng)建邏輯都放到一個工廠類中,會導(dǎo)致這個工廠類變得很復(fù)雜。
除此之外,在某些場景下,如果對象不可復(fù)用,那工廠類每次都要返回不同的對象。如果我們使用簡單工廠模式來實現(xiàn),就只能選擇第一種包含 if 分支邏輯的實現(xiàn)方式。如果我們還想避免煩人的 if-else 分支邏輯,這個時候,我們就推薦使用工廠方法模式。
抽象工廠(Abstract Factory)
抽象工廠模式的應(yīng)用場景比較特殊,沒有前兩種常用,我們簡單了解一下
簡單工廠只是對可樂產(chǎn)品進行了抽象,工廠方法是對可樂工廠進行抽象,抽象工廠是對工廠方法的再次抽象
光從概念可能不好理解,我們來個實例
需求:現(xiàn)在產(chǎn)品線調(diào)整了,我們生產(chǎn)的可樂 雖然有各自的品牌但是都是透明瓶子,我們要做出自己的特點.需要給不同品牌的可樂噴涂不同的顏色瓶身.
思考:如果此時我們將可樂的生產(chǎn)和顏色的噴涂都耦合在工廠方法的代碼中,后續(xù)調(diào)整會很麻煩,也違背了開閉原則,對拓展開放,對修改關(guān)閉,那么此時我們使用抽象工廠就比較合適了
public abstract class ColaAbstractFactory {//創(chuàng)建抽象工廠類
abstract ColaFactory getCola(String cola);
abstract ColorFactory getColor(String color);
}
public class ColaAbstractFactoryImpl extends ColaAbstractFactory {
//實現(xiàn)抽象類
public ColaFactory getCola(String cola) {
if ("cocacola".equals(cola)) {
return new CocaColaFactoryImpl();
} else if ("fake".equals(cola)) {
return new FakeColaFactoryImpl();
} else if ("pepsi".equals(cola)) {
return new PepsiColaFactoryImpl();
} else
return null;
}
public ColorFactory getColor(String color) {
if ("yellow".equals(color)) {
return new YellowColorFactoryImpl();
} else if ("blue".equals(color)) {
return new BlueColorFactoryImpl();
} else if ("red".equals(color)) {
return new RedColorFactoryImpl();
} else
return null;
}
}
public class RedColorFactoryImpl implements ColorFactory {//對不同顏色的需求進行噴涂.其它顏色類似就不重復(fù)貼了
public String getColor() {
System.out.println("噴涂紅色瓶身");
return "紅色瓶子";
}
}
最終我們想要獲得可樂+紅色瓶身
public static String getColaAndColor(String cola,String color){
ColaAbstractFactoryImpl colaAbstractFactory = new ColaAbstractFactoryImpl();
ColaFactory cola = colaAbstractFactory.getCola(cola);
ColorFactory red = colaAbstractFactory.getColor(color);
Cola col = cola.getCola();
String colo = red.getColor();
return col.getCola()+"-"+colo;
}
public static void main(String[] args) {
String colaAndColor = FactoryProducer.getColaAndColor("cocacola", "red");
System.out.println(colaAndColor);
}
//output:
噴涂紅色
生產(chǎn)可口可樂
可口可樂-紅色瓶子
