光氏飲品升級了 --- 工廠方法模式

anly_jun發表於2016-11-21

前情提要

上集講到, 小光的熱乾麵店, 開始搭配提供飲料了. 再加上美女表妹的助陣, 生意是紅紅火火啊.

然而, 事情也不是盡善盡美的, 慢慢小光就聽到了一些的客戶的聲音: 酸梅湯太酸了, 能調好點嗎? 天冷了能來點熱飲嗎?

客戶可是上帝啊, 小光立馬就著手改進.

表妹的抱怨

帶著客戶的聲音, 小光找表妹聊了下, 想讓表妹修改下當前的酸梅湯泡製比例, 另外再增加一些熱飲的泡製.

沒想到, 表妹一聽到著就很反對: "我現在已經記得太多了, 你這麼不定時的修改, 增加, 我更容易記混, 到時候更出問題了". (職責太重)

小光一想, 是啊, 我把自己從做熱乾麵新增各種配料的煩惱中釋放出來了(通過Builder模式). 不能讓表妹也陷入這樣的煩惱啊.

解決之路

可是怎麼才能更好的解決這個問題呢?
要是我有很多個表妹就好了, 每個表妹負責一種飲料的泡製, 小光想著. 嗯~, 很多個表妹?! 小光微微一笑, 計上心頭.

小光買來很多個迷你飲水機, 一個裝一種飲料, 並且貼上相應的標籤, 如此這般:

光氏飲品升級了 --- 工廠方法模式

每個迷你飲水機作為一個飲料機, 用來生產不同的飲料. 表妹只有根據使用者的需求選擇不同的飲料機打出飲料即可.

這樣, 表妹也無需關注飲料的生產過程了, 不用記那麼多的飲料配置方式了. 如果想要新增飲品, 再弄一臺飲料機就行了.

來看看對應關係

這是沒有標籤的飲水機(飲料機):

public interface IBeverageMachine {

    Drink makeDrink();
}複製程式碼

這是貼了不同飲料型別的飲料機:

public class OrangeJuiceMachine implements IBeverageMachine {
    @Override
    public Drink makeDrink() {
        return new OrangeJuice().make();
    }
}

public class CokeMachine implements IBeverageMachine {
    @Override
    public Drink makeDrink() {
        return new Coke().make();
    }
}

public class PlumJuiceMachine implements IBeverageMachine {
    @Override
    public Drink makeDrink() {
        return new PlumJuice().make();
    }
}複製程式碼

這是那些飲料(還是有一個抽象繼承關係):

public abstract class Drink {

    private String name;
    private String instantPackage;

    public Drink make() {
        this.name = getName();
        this.instantPackage = getInstantPackage();
        return this;
    }

    abstract String getInstantPackage();
    abstract String getName();

    @Override
    public String toString() {
        return "This is a cup of:" + this.name;
    }
}

public class Coke extends Drink {
    @Override
    String getInstantPackage() {
        return "速溶可樂粉";
    }

    @Override
    String getName() {
        return "可樂";
    }
}

public class OrangeJuice extends Drink {
    @Override
    String getInstantPackage() {
        return "速溶橙汁粉";
    }

    @Override
    String getName() {
        return "橙汁";
    }
}

public class PlumJuice extends Drink {
    @Override
    String getInstantPackage() {
        return "速溶酸梅粉";
    }

    @Override
    String getName() {
        return "酸梅湯";
    }
}複製程式碼

相比上一篇簡單工廠中的飲料, 我們將打包這個操作從飲料這個物件中移除了, 目前的飲料物件中只是一些簡單的屬性.
為什麼要這麼做呢? 大家可以用自己物件導向程式設計思想的腦洞自由發揮下, 下期說說我的想法.

現在表妹的工作就變得簡單了:

public class Cousins {

    private IBeverageMachine mBeverageMachine;

    private void setBeverageMachine(IBeverageMachine machine) {
        this.mBeverageMachine = machine;
    }

    private Drink takeDrink() {
        if (mBeverageMachine == null) throw new NullPointerException("Should set Beverage Machine firstly.");

        return mBeverageMachine.makeDrink();
    }

    public static void main(String[] args) {

        Cousins cousins = new Cousins();

        // for A
        cousins.setBeverageMachine(new OrangeJuiceMachine());
        Drink drink = cousins.takeDrink();
        System.out.println(drink);

        // for B
        cousins.setBeverageMachine(new CokeMachine());
        System.out.println(cousins.takeDrink());
    }
}複製程式碼

當A要橙汁時, 表妹去OrangeJuiceMachine裝一杯, 當B需要可樂時, 表妹再去CokeMachine拿:

This is a cup of:橙汁
This is a cup of:可樂複製程式碼

表妹的工作變得更簡單了, 工作效率也更高了, 也更能微笑面對顧客了, 哈哈...

想要奶茶的C顧客

這天, 來了一位顧客D, 問: "老闆, 有沒有熱奶茶啊?". 考驗小光的程式的時候到了. 很快, 小光copy出了一個奶茶機(擴充套件開放), 同時也無需修改原來的那些個飲料機程式(修改關閉), 不會因此而耽誤生意.

新增奶茶飲料:

public class MilkTea extends Drink {
    @Override
    String getInstantPackage() {
        return "速溶奶茶粉";
    }

    @Override
    String getName() {
        return "奶茶";
    }
}複製程式碼

奶茶機:

public class MilkTeaMachine implements IBeverageMachine {
    @Override
    public Drink makeDrink() {
        return new MilkTea().make();
    }
}複製程式碼

現在的檯面:

光氏飲品升級了 --- 工廠方法模式

表妹的工作也很簡單, 去奶茶機那兒接奶茶就是了:

// for D
cousins.setBeverageMachine(new MilkTeaMachine());
System.out.println(cousins.takeDrink());複製程式碼

D拿到的:

This is a cup of:奶茶複製程式碼

故事之後

照例, 我們先來畫出現在的類對應關係:

光氏飲品升級了 --- 工廠方法模式

實際上這個就是工廠方法模式.

幾個點:
1, 為何叫工廠方法, 是因為每個工廠有一個方法來建立產品.
2, 每個產品對應一個工廠例項來生產這個產品例項.
3, 因為產品和其對應的工廠都與其他產品分離, 我們可以很輕易的去增加新的產品和其對應的工廠, 而不改變原來的結構. (開閉原則, 實際上還蘊含了職責單一)

擴充套件閱讀

工廠方法模式如同Buidler模式, 是一些開源庫中非常常見的用來建立例項的設計模式.

例如OkHttp中ModelLoader相關的實現:

光氏飲品升級了 --- 工廠方法模式

看對應關係就跟清晰了, 就不一一類比了.

小光看著這一排飲料機, 成就感悠然而生, 彷彿又回到了那個徹夜編碼的歲月.

相關文章