作者:湯圓

個人博客: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就可以了);

但是缺點也很明顯,細心的朋友可能發現了,就是如果想要增加其他結構的椅子,比如躺椅,那么就需要先改動 椅子工廠接口(增加躺椅的制作過程),再在每個實現工廠類中去實現。

總結

簡單工廠模式,簡單好用,缺點是不易擴展,違反了開閉原則;

工廠方法模式,可擴展,但是工廠類過多,會導致代碼繁重;

抽象工廠模式,可擴展,工廠類也不會很多,但是這里的擴展只是種類層面的擴展,如果是結構層面的還是不易擴展,也會違反開閉原則。

這三種工廠模式都屬于創建者型模式。