天天看點

寂然解讀設計模式 - 工廠模式 - 簡單工廠模式

I walk very slowly, but I never walk backwards            

工廠模式 - 簡單工廠模式

​ 寂然

大家好~,我是寂然,本節課呢,我們來看下一個,工廠模式, 工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一,無論是實際應用還是面試都非常高頻和廣泛,話不多說,那我們開始啟程吧

案例引出 - 披薩訂購

那在聊工廠模式之前,我們現來看一個需求

有這樣一個披薩店的需求,披薩的種類很多(比如 GreekPizz、CheesePizz 等)

披薩的制作有 prepare,bake,cut,box 等

要求:完成披薩店訂購功能,便于披薩種類的擴充,便于維護

拿到這個需求,大家會怎麼實作呢?我們先不要想着工廠模式,用平時的思路,來完成下需求

解決方案一 - 一般實作方式

首先我們用一般常用的實作方式來解決,比如我們定義一個抽象類 pizza,因為我們 Pizza 的種類有很多,最容易想到的就是定義一個模闆,定義好 Pizza 的通用方法,比如,披薩的制作都需要 prepare,bake,cut,box 等方法,就可以定義到抽象類 Pizza裡面,具體種類的 Pizza 繼承抽象父類 Pizza ,就可以使用裡面的通用方法了,同時子類可以重寫方法,實作子類特有的業務邏輯,那根據上面的思路,對應的類圖如下圖所示

寂然解讀設計模式 - 工廠模式 - 簡單工廠模式

根據類圖,我們先把基礎的類定義出來,代碼示例如下圖所示

//抽象類接口 Pizza
public abstract class Pizza {

    //定義一個屬性,披薩的名稱,并給定set方法
    protected String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //認為不同的披薩,準備的原材料不同,是以定義成抽象方法
    public abstract void prepare();

    //烘焙方法
    public void bake() {

        System.out.println(name + "正在烘焙中");
    }

    //切割方法
    public void cut() {

        System.out.println(name + "正準備把披薩大卸八塊");
    }

    //打包方法
    public void box() {

        System.out.println(name + "将披薩打包給顧客");
    }
}

//希臘披薩
public class GreekPizza extends Pizza {

    @Override
    public void prepare() {

        System.out.println("準備希臘披薩的原材料");
    }
}

//奶酪披薩
public class CheesePizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("準備原材料 奶酪,芝士等");
    }
}
           

OK,架構有了,當然我們還要完成訂購披薩的功能,建立 OrderPizza ,寫入訂購披薩的邏輯,同時我們希望擷取客戶想要訂購的披薩種類,進行訂購并制作,完整的實作代碼如下圖所示

//訂購披薩
public class OrderPizza {

    //當然後面會進行改進,這是第一版的實作方式
    //構造器
    public OrderPizza(){

        Pizza pizza = null;

        String orderType; //訂購披薩的類型

        while(true){

            orderType = getType();//給定一個固定值先

            if (orderType.equals("GreekPizza")){

                pizza = new GreekPizza();
                pizza.setName("GreekPizza");

            }else if (orderType.equals("CheesePizza")){

                pizza = new CheesePizza();
                pizza.setName("CheesePizza");

            }else{

                break;
            }
            //輸出 Pizza 制作過程
            pizza.prepare();

            pizza.bake();

            pizza.cut();

            pizza.box();
        }
    }

    //定義方法擷取客戶希望訂購的披薩種類
    private String getType(){

        System.out.println("你想訂購那個種類的Pizza呢?");

        Scanner scanner = new Scanner(System.in);

        String str = scanner.next();

        return str;
    }
}

//披薩商店,發出披薩訂購任務
public class PizzaStore {

    public static void main(String[] args) {

        new OrderPizza(); //構造器中完成相應功能
    }
}           

方案分析

OK,運作過後,首先保證實作了簡易的訂購披薩的需求,運作結果如下圖所示

寂然解讀設計模式 - 工廠模式 - 簡單工廠模式

那我們來談談這種實作方式的利弊

優點:符合我們一般的寫法,容易了解和接受

缺點:很明顯,違反了設計模式的開閉原則,對擴充開放,對修改關閉,即當我們給類增加新功能的時候,盡量不修改代碼,或者盡量少修改代碼,而上面的實作方式,假設我們新增 FruitPizza,我們需要做如下改動才能實作

//新定義水果披薩類
public class FruitPizza extends Pizza {

    @Override
    public void prepare() {
        System.out.println("準備原材料 香蕉,鳳梨等");
    }
}

//新增加判斷條件,如果是 FruitPizza 的處理邏輯
else if (orderType.equals("FruitPizza")){

    pizza = new FruitPizza();
    pizza.setName("FruitPizza");

}           

改進思路

其實修改代碼是在允許範圍内的,但是如果我們在其他的地方也有建立 Pizza 的代碼,那就也需要修改,而建立 Pizza 的代碼,往往有多處,針對這個問題,我們可以有這樣一個思路:把建立 Pizza 對象的功能封裝到一個類中,這樣我們有新的 Pizza 種類的時候,隻需要修改該類即可,其他地方涉及到建立 Pizza 對象的代碼就不需要修改了,這種思路其實就是簡單工廠模式

基本介紹 - 簡單工廠模式

簡單工廠模式是屬于建立型模式,是工廠模式的一種,簡單工廠模式是由一個工廠對象決定建立出哪一種産品/類的執行個體,簡單工廠模式是工廠模式家族中最簡單實用的模式

簡單工廠模式:定義了一個建立對象的類,由這個類來封裝執行個體化對象的行為,在簡單工廠模式中,可以根據參數的不同傳回不同類的執行個體

在軟體開發中,當我們涉及到大量的建立某種或者某類對象時,就會使用到工廠模式,你隻需要使用工廠對象來需建立對象即可,具體的建立細節被工廠對象封裝起來

解決方案二 - 簡單工廠模式

那我們使用簡單工廠模式的思想,來對代碼進行重構,首先定義 SimpleFactory 類,讓該類作為工廠對象,來封裝執行個體化對象的行為,原來 訂購披薩類 OrderPizza 裡不再需要建立Pizza,調用SimpleFactory 類執行個體化對象的方法即可,代碼示例如下圖所示

// 案例示範 - 使用簡單工廠模式
// 簡單工廠類
public class SimpleFactory {

    //執行個體化對象的方法
    public Pizza createPizza(String orderType){

        Pizza pizza = null;

        if (orderType.equals("GreekPizza")){

            pizza = new GreekPizza();
            pizza.setName("GreekPizza");

        }else if (orderType.equals("CheesePizza")){

            pizza = new CheesePizza();
            pizza.setName("CheesePizza");

        }else if (orderType.equals("FruitPizza")){

            pizza = new FruitPizza();
            pizza.setName("FruitPizza");

        }
        return pizza;
    }
}           

上面我們按照簡單工廠模式的思想,把按需建立對象的行為封裝到 SimpleFactory 工廠類中,那現在 OrderPizza 中依賴 setSimpleFactory 即可,比如以成員屬性的形式,那擷取客戶想要訂購的披薩種類,進行訂購并制作的邏輯我們另外封裝一個方法,或者直接封裝在 simpleFactory 的 set() 方法裡 ,那根據這樣的想法,示例代碼如下

//建立簡單工廠類對象,給定set方法
    SimpleFactory simpleFactory;

    Pizza pizza = null; //初始化Pizza對象,初始值為null

    //構造器裡調用 setSimpleFactory
    public OrderPizza(SimpleFactory simpleFactory){

        setSimpleFactory(simpleFactory);
    }

    public void setSimpleFactory(SimpleFactory simpleFactory) {

        String ordertype = "";

        this.simpleFactory = simpleFactory;

        //可能是反複訂購
        while (true){

            ordertype = getType();//得到使用者想要的類型

            pizza = this.simpleFactory.createPizza(ordertype);

            if (pizza != null){ //表示訂購成功
                //輸出 Pizza 制作過程
                pizza.prepare();

                pizza.bake();

                pizza.cut();

                pizza.box();

            }else{

                System.out.println("披薩訂購失敗,沒有你要的Pizza");
                break;
            }
        }
    }

//披薩商店,發出披薩訂購任務
public class PizzaStore {

    public static void main(String[] args) {

         //new OrderPizza();
         //使用簡單工廠模式
         new OrderPizza(new SimpleFactory());
    }
}           

OK,上面我們用簡單工廠模式将代碼重構完畢,首先保訂購披薩的需求運作正常,運作結果如下圖所示

寂然解讀設計模式 - 工廠模式 - 簡單工廠模式

那我們來聊聊這種方式的好處或者說這種情況下,使用簡單工廠模式處理的好處,假設我們新增第四種Pizza,除了對該Pizza進行定義以外,隻需要在 SimpleFactory 工廠類,加一條 else if 判斷語句即可,其他地方不需要做改動,因為在簡單工廠模式中,工廠類負責封裝執行個體化對象的細節,是以業務邏輯中建立 Pizza 的代碼隻有這一處

簡單工廠模式也叫靜态工廠模式,舉個例子,還可以在 SimpleFactory 工廠類中把執行個體化對象的方法 createPizza 定義為靜态,這樣的話 OrderPizza 裡直接通過類名來調用 createPizza 即可,不需要通過構造器了,也是可以的,這裡就不做示範了

下節預告

OK,由于篇幅的限制,本節内容就先到這裡,下一節,我們接着來聊工廠模式,同樣是披薩訂購的案例,我們進行擴充,引出第二種要介紹的工廠方法模式,最後,希望大家在學習的過程中,能夠感覺到設計模式的有趣之處,高效而愉快的學習,那我們下期見~