前情提要
上集講到, 小光的熱乾麵店, 開始搭配提供飲料了. 再加上美女表妹的助陣, 生意是紅紅火火啊.
然而, 事情也不是盡善盡美的, 慢慢小光就聽到了一些的客戶的聲音: 酸梅湯太酸了, 能調好點嗎? 天冷了能來點熱飲嗎?
客戶可是上帝啊, 小光立馬就著手改進.
表妹的抱怨
帶著客戶的聲音, 小光找表妹聊了下, 想讓表妹修改下當前的酸梅湯泡製比例, 另外再增加一些熱飲的泡製.
沒想到, 表妹一聽到著就很反對: "我現在已經記得太多了, 你這麼不定時的修改, 增加, 我更容易記混, 到時候更出問題了". (職責太重)
小光一想, 是啊, 我把自己從做熱乾麵新增各種配料的煩惱中釋放出來了(通過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相關的實現:
看對應關係就跟清晰了, 就不一一類比了.
小光看著這一排飲料機, 成就感悠然而生, 彷彿又回到了那個徹夜編碼的歲月.