前情提要
上集講到, 小光的熱干面店, 開(kāi)始搭配提供飲料了. 再加上美女表妹的助陣, 生意是紅紅火火啊.
然而, 事情也不是盡善盡美的, 慢慢小光就聽(tīng)到了一些的客戶(hù)的聲音: 酸梅湯太酸了, 能調(diào)好點(diǎn)嗎? 天冷了能來(lái)點(diǎn)熱飲嗎?
客戶(hù)可是上帝啊, 小光立馬就著手改進(jìn).
所有示例源碼已經(jīng)上傳到Github, 戳這里
表妹的抱怨
帶著客戶(hù)的聲音, 小光找表妹聊了下, 想讓表妹修改下當(dāng)前的酸梅湯泡制比例, 另外再增加一些熱飲的泡制.
沒(méi)想到, 表妹一聽(tīng)到著就很反對(duì): “我現(xiàn)在已經(jīng)記得太多了, 你這么不定時(shí)的修改, 增加, 我更容易記混, 到時(shí)候更出問(wèn)題了”. (職責(zé)太重)
小光一想, 是啊, 我把自己從做熱干面添加各種配料的煩惱中釋放出來(lái)了(通過(guò)Builder模式). 不能讓表妹也陷入這樣的煩惱啊.
解決之路
可是怎么才能更好的解決這個(gè)問(wèn)題呢?
要是我有很多個(gè)表妹就好了, 每個(gè)表妹負(fù)責(zé)一種飲料的泡制, 小光想著. 嗯~, 很多個(gè)表妹?! 小光微微一笑, 計(jì)上心頭.
小光買(mǎi)來(lái)很多個(gè)迷你飲水機(jī), 一個(gè)裝一種飲料, 并且貼上相應(yīng)的標(biāo)簽, 如此這般:
每個(gè)迷你飲水機(jī)作為一個(gè)飲料機(jī), 用來(lái)生產(chǎn)不同的飲料. 表妹只有根據(jù)用戶(hù)的需求選擇不同的飲料機(jī)打出飲料即可.
這樣, 表妹也無(wú)需關(guān)注飲料的生產(chǎn)過(guò)程了, 不用記那么多的飲料配置方式了. 如果想要新增飲品, 再弄一臺(tái)飲料機(jī)就行了.
來(lái)看看對(duì)應(yīng)關(guān)系
這是沒(méi)有標(biāo)簽的飲水機(jī)(飲料機(jī)):
public interface IBeverageMachine {
Drink makeDrink();
}
這是貼了不同飲料類(lèi)型的飲料機(jī):
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();
}
}
這是那些飲料(還是有一個(gè)抽象繼承關(guān)系):
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 "速溶可樂(lè)粉";
}
@Override
String getName() {
return "可樂(lè)";
}
}
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 "酸梅湯";
}
}
相比上一篇簡(jiǎn)單工廠中的飲料, 我們將打包這個(gè)操作從飲料這個(gè)對(duì)象中移除了, 目前的飲料對(duì)象中只是一些簡(jiǎn)單的屬性.
為什么要這么做呢? 大家可以用自己面向?qū)ο缶幊趟枷氲哪X洞自由發(fā)揮下, 下期說(shuō)說(shuō)我的想法.
現(xiàn)在表妹的工作就變得簡(jiǎn)單了:
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());
}
}
當(dāng)A要橙汁時(shí), 表妹去OrangeJuiceMachine裝一杯, 當(dāng)B需要可樂(lè)時(shí), 表妹再去CokeMachine拿:
This is a cup of:橙汁
This is a cup of:可樂(lè)
表妹的工作變得更簡(jiǎn)單了, 工作效率也更高了, 也更能微笑面對(duì)顧客了, 哈哈…
想要奶茶的C顧客
這天, 來(lái)了一位顧客D, 問(wèn): “老板, 有沒(méi)有熱奶茶啊?”. 考驗(yàn)小光的程序的時(shí)候到了. 很快, 小光copy出了一個(gè)奶茶機(jī)(擴(kuò)展開(kāi)放), 同時(shí)也無(wú)需修改原來(lái)的那些個(gè)飲料機(jī)程序(修改關(guān)閉), 不會(huì)因此而耽誤生意.
新增奶茶飲料:
public class MilkTea extends Drink {
@Override
String getInstantPackage() {
return "速溶奶茶粉";
}
@Override
String getName() {
return "奶茶";
}
}
奶茶機(jī):
public class MilkTeaMachine implements IBeverageMachine {
@Override
public Drink makeDrink() {
return new MilkTea().make();
}
}
現(xiàn)在的臺(tái)面:
表妹的工作也很簡(jiǎn)單, 去奶茶機(jī)那兒接奶茶就是了:
// for D
cousins.setBeverageMachine(new MilkTeaMachine());
System.out.println(cousins.takeDrink());
D拿到的:
This is a cup of:奶茶
故事之后
照例, 我們先來(lái)畫(huà)出現(xiàn)在的類(lèi)對(duì)應(yīng)關(guān)系:
實(shí)際上這個(gè)就是工廠方法模式.
幾個(gè)點(diǎn):
1, 為何叫工廠方法, 是因?yàn)槊總€(gè)工廠有一個(gè)方法來(lái)創(chuàng)建產(chǎn)品.
2, 每個(gè)產(chǎn)品對(duì)應(yīng)一個(gè)工廠實(shí)例來(lái)生產(chǎn)這個(gè)產(chǎn)品實(shí)例.
3, 因?yàn)楫a(chǎn)品和其對(duì)應(yīng)的工廠都與其他產(chǎn)品分離, 我們可以很輕易的去增加新的產(chǎn)品和其對(duì)應(yīng)的工廠, 而不改變?cè)瓉?lái)的結(jié)構(gòu). (開(kāi)閉原則, 實(shí)際上還蘊(yùn)含了職責(zé)單一)
擴(kuò)展閱讀
工廠方法模式如同Buidler模式, 是一些開(kāi)源庫(kù)中非常常見(jiàn)的用來(lái)創(chuàng)建實(shí)例的設(shè)計(jì)模式.
例如OkHttp中ModelLoader相關(guān)的實(shí)現(xiàn):
看對(duì)應(yīng)關(guān)系就跟清晰了, 就不一一類(lèi)比了.
小光看著這一排飲料機(jī), 成就感悠然而生, 仿佛又回到了那個(gè)徹夜編碼的歲月.