作者:湯圓
個(gè)人博客:javalover.cc
前言
工廠我們都知道,就是生產(chǎn)東西的地方;
以前的農(nóng)業(yè)時(shí)代,我們需要啥東西,都是自己做,比如椅子、桌子;
后來(lái)到了工業(yè)時(shí)代,我們需要啥東西,大部分都是工廠做,你只需要告訴工廠需要的東西。
其實(shí)軟件中的工廠設(shè)計(jì)模式,也是類似:不需要我們自己去創(chuàng)建對(duì)象,只需要告訴工廠類,需要啥對(duì)象,工廠類會(huì)幫你創(chuàng)建。
下面我們循序漸進(jìn)來(lái)介紹下工廠模式
目錄
- 制作一種椅子
- 制作多種椅子
- 創(chuàng)建一個(gè)椅子工廠(簡(jiǎn)單工廠模式)
- 創(chuàng)建多個(gè)椅子工廠(工廠方法模式)
- 創(chuàng)建多個(gè)椅子工廠(抽象工廠模式)
正文
1. 制作一種椅子
這個(gè)是最簡(jiǎn)單的了,就是誰(shuí)需要,誰(shuí)就創(chuàng)建一個(gè),很方便;
package pattern.factory.nofactory;/** * 沒(méi)有工廠,直接創(chuàng)建椅子 */public class NoFactory { public static void main(String[] args) { Chair chair = new Chair(); chair.prepare(); chair.make(); chair.box(); } static class Chair { public String name = "小椅子"; public void prepare() { System.out.println(name + "的原材料是:A,B,C"); } public void make(){ System.out.println(name + "制作中"); } public void box(){ System.out.println(name + "打包中"); } }}
2. 制作多種椅子
過(guò)了幾天,小李覺(jué)得這種椅子不舒服,沒(méi)有靠背,于是又創(chuàng)建了帶靠背的椅子
package pattern.factory.nofactory;/** * 沒(méi)有工廠,直接創(chuàng)建椅子(多種椅子) */public class NoFactory2 { public static void main(String[] args) { Chair chair = new ChairA(); chair.prepare(); chair.make(); chair.box(); Chair chairB = new ChairB(); chairB.prepare(); chairB.make(); chairB.box(); }}abstract class Chair { public String name; public abstract void prepare(); public void make(){ System.out.println(name + "制作中"); } public void box(){ System.out.println(name + "打包中"); }}class ChairA extends Chair { public ChairA() { this.name = "小椅子"; } @Override public void prepare() { System.out.println(name + "的原材料是:A,B,C"); }}class ChairB extends Chair { public ChairB() { this.name = "靠背椅"; } @Override public void prepare() { System.out.println(name + "的原材料是:A2,B2,C2"); }}
這樣看來(lái),好像問(wèn)題也不大;
可以是如果不止兩種,而是十幾種幾十種呢?
此時(shí)再一個(gè)個(gè)創(chuàng)建就很麻煩了;
于是就有了工廠模式。
其實(shí)不止類型的增加需要工廠,數(shù)量的增加同樣也需要工廠(流水線制作提高效率)
3. 創(chuàng)建一個(gè)椅子工廠(簡(jiǎn)單工廠模式)
簡(jiǎn)單工廠模式:定義一個(gè)工廠類,它可以根據(jù)參數(shù)的不同返回不同類的實(shí)例,被創(chuàng)建的實(shí)例通常都具有共同的父類
小李花錢建了一個(gè)工廠,專門做各種各樣的椅子,這樣他每天都可以換不同的椅子坐;
大概的流程就是小李需要什么椅子,就告訴工廠,工廠來(lái)做(不再需要自己做)。
package pattern.factory.simple1;public class SimpleFactory1 { public static void main(String[] args) { SimpleChairFactory simpleChairFactory = new SimpleChairFactory(); simpleChairFactory.order("小椅子"); simpleChairFactory.order("靠背椅"); }}class SimpleChairFactory { public Chair chair; public void order(String name){ if(name == "小椅子"){ chair = new ChairA(); }else if(name == "靠背椅"){ chair = new ChairB(); }else{ chair = null; } if(chair != null){ chair.prepare(); chair.make(); chair.box(); }else{ System.out.println("找不到對(duì)應(yīng)的椅子"); } }}abstract class Chair { public String name; public abstract void prepare(); public void make(){ System.out.println(name + "制作中"); } public void box(){ System.out.println(name + "打包中"); }}class ChairA extends Chair { public ChairA() { this.name = "小椅子"; } @Override public void prepare() { System.out.println(name + "的原材料是:A,B,C"); }}class ChairB extends Chair { public ChairB() { this.name = "靠背椅"; } @Override public void prepare() { System.out.println(name + "的原材料是:A2,B2,C2"); }}
上面這個(gè)就是簡(jiǎn)單工廠模式,通過(guò)把自己的需求告訴工廠,工廠去做出你想要的東西;
4. 創(chuàng)建多個(gè)椅子工廠(工廠方法模式)
工廠方法模式:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定將哪一個(gè)類實(shí)例化。
上面的簡(jiǎn)單工廠模式,確實(shí)很簡(jiǎn)單,用起來(lái)也很方便;
但是有一個(gè)很大的缺點(diǎn),就是如果需要增加椅子的種類,那么就需要修改工廠類的源代碼;
這樣一來(lái)就違背了開(kāi)閉原則:對(duì)類的擴(kuò)展開(kāi)放,對(duì)類的修改關(guān)閉;
所以我們需要對(duì)其進(jìn)行改進(jìn),創(chuàng)建多個(gè)工廠子類,來(lái)實(shí)現(xiàn)不同的創(chuàng)建任務(wù)。
package pattern.factory.method;/** * 工廠方法模式:將工廠類抽象出來(lái),子類去實(shí)現(xiàn)對(duì)象的創(chuàng)建 */public class MethodFactory { public static void main(String[] args) { SmallChairFactory smallFactory = new SmallChairFactory(); smallFactory.order(); BackChairFactory backFactory = new BackChairFactory(); backFactory.order(); }}interface ChairFactory{ void order();}class SmallChairFactory implements ChairFactory{ public Chair chair; public void order(){ chair = new ChairA(); chair.prepare(); chair.make(); chair.box(); }}class BackChairFactory implements ChairFactory{ public Chair chair; public void order(){ chair = new ChairB(); chair.prepare(); chair.make(); chair.box(); }}abstract class Chair { public String name; public abstract void prepare(); public void make(){ System.out.println(name + "制作中"); } public void box(){ System.out.println(name + "打包中"); }}class ChairA extends Chair { public ChairA() { this.name = "小椅子"; } @Override public void prepare() { System.out.println(name + "的原材料是:A,B,C"); }}class ChairB extends Chair { public ChairB() { this.name = "靠背椅"; } @Override public void prepare() { System.out.println(name + "的原材料是:A2,B2,C2"); }}
5. 創(chuàng)建多個(gè)椅子工廠(抽象工廠模式)
抽象工廠模式:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)須指定它們具體的類。
上面的工廠方法模式,雖然解決了簡(jiǎn)單工廠模式的問(wèn)題(不好擴(kuò)展,單個(gè)類任務(wù)繁重),但是它本身也是有缺點(diǎn)的;
就是工廠方法模式中,一個(gè)工廠子類只負(fù)責(zé)生產(chǎn)一種產(chǎn)品,所以后期增加產(chǎn)品時(shí),會(huì)導(dǎo)致工廠類過(guò)多;
這時(shí)就需要將產(chǎn)品進(jìn)行一個(gè)簡(jiǎn)單的分類(按特定的屬性分類,比如按材質(zhì)分類):比如木頭椅子,全都讓一個(gè)廠去做;塑料椅子,讓另一個(gè)廠去做。
然后每個(gè)材質(zhì)的椅子,內(nèi)部再按結(jié)構(gòu)分類(小椅子,靠背椅);
這個(gè)就是抽象工廠模式的核心:將產(chǎn)品進(jìn)行分類,然后分配到不同的工廠子類中。
下面這個(gè)例子是先按照材質(zhì)進(jìn)行大的分類,再按照結(jié)構(gòu)進(jìn)行小的分類:
package pattern.factory.abstract1;/** * 抽象工廠模式:將工廠類抽象出來(lái),再把產(chǎn)品分類,每個(gè)子工廠生產(chǎn)特定類型的產(chǎn)品 * * 是工廠方法模式的升級(jí)版,工廠方法模式是一個(gè)工廠只做一個(gè)產(chǎn)品,而抽象工廠模式是一個(gè)工廠做一類產(chǎn)品 */public class AbstractFactory { public static void main(String[] args) { // 木頭 WoodChairFactory woodChairFactory = new WoodChairFactory(); woodChairFactory.orderSmallChair(); woodChairFactory.orderBackChair(); // 塑料 PlasticChairFactory plasticChairFactory = new PlasticChairFactory(); plasticChairFactory.orderSmallChair(); plasticChairFactory.orderBackChair(); }}interface ChairFactory{ void orderSmallChair(); void orderBackChair();}// 木頭椅子 工廠class WoodChairFactory implements ChairFactory{ public WoodChair chair; @Override public void orderSmallChair() { chair = new WoodSmallChair(); chair.prepare(); chair.make(); chair.box(); } @Override public void orderBackChair() { chair = new WoodBackChair(); chair.prepare(); chair.make(); chair.box(); }}// 塑料椅子 工廠class PlasticChairFactory implements ChairFactory{ public PlasticChair chair; @Override public void orderSmallChair() { chair = new PlasticSmallChair(); chair.prepare(); chair.make(); chair.box(); } @Override public void orderBackChair() { chair = new PlasticBackChair(); chair.prepare(); chair.make(); chair.box(); }}abstract class Chair { public String type; // 木頭/塑料 public String name; // 小椅子/靠背椅 public void prepare(){ System.out.println(type+name + "的制作步驟是:A,B,C"); } public void make(){ System.out.println(type+name + "制作中"); } public void box(){ System.out.println(type+name + "打包中"); }}// 木頭椅class WoodChair extends Chair { public WoodChair() { this.type = "木頭-"; }}class WoodSmallChair extends WoodChair{ public WoodSmallChair(){ this.name = "小椅子"; }}class WoodBackChair extends WoodChair{ public WoodBackChair(){ this.name = "靠背椅"; }}// 塑料椅class PlasticChair extends Chair { public PlasticChair() { this.type = "塑料-"; }}class PlasticSmallChair extends PlasticChair{ public PlasticSmallChair(){ this.name = "小椅子"; }}class PlasticBackChair extends PlasticChair{ public PlasticBackChair(){ this.name = "靠背椅"; }}
上面的這個(gè)抽象工廠模式的例子,雖然現(xiàn)在增加椅子的種類很方便了,只需要擴(kuò)展一個(gè)椅子的子類就可以(比如鐵的椅子,只需要?jiǎng)?chuàng)建 IronChair 繼承 Chair就可以了);
但是缺點(diǎn)也很明顯,細(xì)心的朋友可能發(fā)現(xiàn)了,就是如果想要增加其他結(jié)構(gòu)的椅子,比如躺椅,那么就需要先改動(dòng) 椅子工廠接口(增加躺椅的制作過(guò)程),再在每個(gè)實(shí)現(xiàn)工廠類中去實(shí)現(xiàn)。
總結(jié)
簡(jiǎn)單工廠模式,簡(jiǎn)單好用,缺點(diǎn)是不易擴(kuò)展,違反了開(kāi)閉原則;
工廠方法模式,可擴(kuò)展,但是工廠類過(guò)多,會(huì)導(dǎo)致代碼繁重;
抽象工廠模式,可擴(kuò)展,工廠類也不會(huì)很多,但是這里的擴(kuò)展只是種類層面的擴(kuò)展,如果是結(jié)構(gòu)層面的還是不易擴(kuò)展,也會(huì)違反開(kāi)閉原則。
這三種工廠模式都屬于創(chuàng)建者型模式。