作者:湯圓
個人博客:javalover.cc
前言
工廠我們都知道,就是生產東西的地方;
以前的農業時代,我們需要啥東西,都是自己做,比如椅子、桌子;
后來到了工業時代,我們需要啥東西,大部分都是工廠做,你只需要告訴工廠需要的東西。
其實軟件中的工廠設計模式,也是類似:不需要我們自己去創建對象,只需要告訴工廠類,需要啥對象,工廠類會幫你創建。
下面我們循序漸進來介紹下工廠模式
目錄
- 制作一種椅子
- 制作多種椅子
- 創建一個椅子工廠(簡單工廠模式)
- 創建多個椅子工廠(工廠方法模式)
- 創建多個椅子工廠(抽象工廠模式)
正文
1. 制作一種椅子
這個是最簡單的了,就是誰需要,誰就創建一個,很方便;
package pattern.factory.nofactory;/** * 沒有工廠,直接創建椅子 */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. 制作多種椅子
過了幾天,小李覺得這種椅子不舒服,沒有靠背,于是又創建了帶靠背的椅子
package pattern.factory.nofactory;/** * 沒有工廠,直接創建椅子(多種椅子) */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"); }}
這樣看來,好像問題也不大;
可以是如果不止兩種,而是十幾種幾十種呢?
此時再一個個創建就很麻煩了;
于是就有了工廠模式。
其實不止類型的增加需要工廠,數量的增加同樣也需要工廠(流水線制作提高效率)
3. 創建一個椅子工廠(簡單工廠模式)
簡單工廠模式:定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類
小李花錢建了一個工廠,專門做各種各樣的椅子,這樣他每天都可以換不同的椅子坐;
大概的流程就是小李需要什么椅子,就告訴工廠,工廠來做(不再需要自己做)。
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("找不到對應的椅子"); } }}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"); }}
上面這個就是簡單工廠模式,通過把自己的需求告訴工廠,工廠去做出你想要的東西;
4. 創建多個椅子工廠(工廠方法模式)
工廠方法模式:定義一個用于創建對象的接口,讓子類決定將哪一個類實例化。
上面的簡單工廠模式,確實很簡單,用起來也很方便;
但是有一個很大的缺點,就是如果需要增加椅子的種類,那么就需要修改工廠類的源代碼;
這樣一來就違背了開閉原則:對類的擴展開放,對類的修改關閉;
所以我們需要對其進行改進,創建多個工廠子類,來實現不同的創建任務。
package pattern.factory.method;/** * 工廠方法模式:將工廠類抽象出來,子類去實現對象的創建 */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. 創建多個椅子工廠(抽象工廠模式)
抽象工廠模式:提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。
上面的工廠方法模式,雖然解決了簡單工廠模式的問題(不好擴展,單個類任務繁重),但是它本身也是有缺點的;
就是工廠方法模式中,一個工廠子類只負責生產一種產品,所以后期增加產品時,會導致工廠類過多;
這時就需要將產品進行一個簡單的分類(按特定的屬性分類,比如按材質分類):比如木頭椅子,全都讓一個廠去做;塑料椅子,讓另一個廠去做。
然后每個材質的椅子,內部再按結構分類(小椅子,靠背椅);
這個就是抽象工廠模式的核心:將產品進行分類,然后分配到不同的工廠子類中。
下面這個例子是先按照材質進行大的分類,再按照結構進行小的分類:
package pattern.factory.abstract1;/** * 抽象工廠模式:將工廠類抽象出來,再把產品分類,每個子工廠生產特定類型的產品 * * 是工廠方法模式的升級版,工廠方法模式是一個工廠只做一個產品,而抽象工廠模式是一個工廠做一類產品 */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 = "靠背椅"; }}
上面的這個抽象工廠模式的例子,雖然現在增加椅子的種類很方便了,只需要擴展一個椅子的子類就可以(比如鐵的椅子,只需要創建 IronChair 繼承 Chair就可以了);
但是缺點也很明顯,細心的朋友可能發現了,就是如果想要增加其他結構的椅子,比如躺椅,那么就需要先改動 椅子工廠接口(增加躺椅的制作過程),再在每個實現工廠類中去實現。
總結
簡單工廠模式,簡單好用,缺點是不易擴展,違反了開閉原則;
工廠方法模式,可擴展,但是工廠類過多,會導致代碼繁重;
抽象工廠模式,可擴展,工廠類也不會很多,但是這里的擴展只是種類層面的擴展,如果是結構層面的還是不易擴展,也會違反開閉原則。
這三種工廠模式都屬于創建者型模式。