【大聖看玩多時,問土地道:“此樹有多少株數?”土地道:“有三千六百株。前面一千二百株,花微果小,三千年一熟,人吃了成仙了道,體健身輕。中間一千二百株,層花甘實,六千年一熟,人吃了霞舉飛升,長生不老。後面一千二百株,紫紋緗核,九千年一熟,人吃了與天地齊壽,日月同庚。”大聖聞言,歡喜無任,當日查明瞭株樹 ...
【大聖看玩多時,問土地道:“此樹有多少株數?”土地道:“有三千六百株。前面一千二百株,花微果小,三千年一熟,人吃了成仙了道,體健身輕。中間一千二百株,層花甘實,六千年一熟,人吃了霞舉飛升,長生不老。後面一千二百株,紫紋緗核,九千年一熟,人吃了與天地齊壽,日月同庚。”大聖聞言,歡喜無任,當日查明瞭株樹,點看了亭閣回府。自此後,三五日一次賞玩,也不交友,也不他游。】
在《西游記》第五回《亂蟠桃大聖偷丹 反天宮諸神捉怪》里有上面這一段關於蟠桃園裡不同種類蟠桃樹的描述,那麼這裡就用蟠桃園為例來描述一下普通工廠模式的運作方式:
蟠桃
package com.tirion.design.simple.factory; public interface FlatPeach { void printLevel(); void printCycleTime(); }
低級蟠桃
package com.tirion.design.simple.factory; public class LowLevelFlatPeach implements FlatPeach { LowLevelFlatPeach(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("低級蟠桃"); } @Override public void printCycleTime() { System.out.println("三千年一熟"); } }
中級蟠桃
package com.tirion.design.simple.factory; public class MiddleLevelFlatPeach implements FlatPeach { MiddleLevelFlatPeach(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("中級蟠桃"); } @Override public void printCycleTime() { System.out.println("六千年一熟"); } }
高級蟠桃
package com.tirion.design.simple.factory; public class HighLevelFlatPeach implements FlatPeach { HighLevelFlatPeach(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("高級蟠桃"); } @Override public void printCycleTime() { System.out.println("九千年一熟"); } }
蟠桃園
package com.tirion.design.simple.factory; public class FlatPeachGarden { public static FlatPeach produce(String level) { System.out.println("生長出..."); if ("low".equals(level)) { return new LowLevelFlatPeach(); } else if ("middle".equals(level)) { return new MiddleLevelFlatPeach(); } else if ("high".equals(level)) { return new HighLevelFlatPeach(); } else { System.out.println("沒有對應等級的蟠桃"); return null; } } }
王母娘娘
package com.tirion.design.simple.factory; public class TheQueenMother { public static void getFlatPeach(String level) { FlatPeach flatPeach = FlatPeachGarden.produce(level); if (flatPeach == null) { System.out.println("王母娘娘沒有得到蟠桃"); } else { System.out.println("王母娘娘獲得了蟠桃"); } } public static void main(String[] args) { TheQueenMother.getFlatPeach("low"); TheQueenMother.getFlatPeach("middle"); TheQueenMother.getFlatPeach("high"); TheQueenMother.getFlatPeach("super high"); } }
這裡的蟠桃園就是一個蟠桃工廠,在這個工廠里有三種產品:三千年一熟的低級蟠桃、六千年一熟的中級蟠桃以及九千年一熟的高級蟠桃,王母娘娘需要蟠桃的時候,就可以通過調用蟠桃園的produce方法,傳入她所需要的蟠桃等級,就可以獲得對應等級的蟠桃。
下麵是上述代碼的執行結果:
生長出...
三千年一熟
低級蟠桃
王母娘娘獲得了蟠桃
生長出...
六千年一熟
中級蟠桃
王母娘娘獲得了蟠桃
生長出...
九千年一熟
高級蟠桃
王母娘娘獲得了蟠桃
生長出...
沒有對應等級的蟠桃
王母娘娘沒有得到蟠桃
這個示例的類圖如下:
從上圖可以看出,蟠桃真正的消費者王母娘娘The Queen Mother,並不需要接觸到具體的蟠桃FlatPeach。當王母娘娘需要蟠桃的時候,她只需要調用工廠類蟠桃園FlatPeachGarden的produce方法,告知它自己需要的蟠桃等級level,就可以獲取到對應的蟠桃了,如果她給了蟠桃園錯誤的指令,則不會獲取到蟠桃。
所以,普通工廠模式的優點在於,產品的消費者並不需要知道產品生產的細節,消費者只需要調用工廠類創建產品的方法就可以了,產品創建的具體邏輯交給了工廠類來獨立處理,這就實現了責任的分離,消費者負責獲取產品,工廠類負責創建產品。
接著我們再看一下普通工廠模式的擴展性如何:
假設現在出現了一個突發情況,蟠桃園的九千年高級蟠桃被孫悟空全部偷吃掉了,蟠桃園工廠目前提供不了九千年高級蟠桃了,我們如何在程式中體現這個邏輯的改動呢?非常簡單,只需要修改蟠桃園類的生產邏輯就可以了。
package com.tirion.design.simple.factory; public class FlatPeachGarden { public static FlatPeach produce(String level) { System.out.println("生長出..."); if ("low".equals(level)) { return new LowLevelFlatPeach(); } else if ("middle".equals(level)) { return new MiddleLevelFlatPeach(); } else if ("high".equals(level)) { System.out.println("高級蟠桃被孫悟空偷吃完了"); return null; // return new HighLevelFlatPeach(); } else { System.out.println("沒有對應等級的蟠桃"); return null; } } }
其他部分代碼不需要改變,程式的執行結果如下:
生長出...
三千年一熟
低級蟠桃
王母娘娘獲得了蟠桃
生長出...
六千年一熟
中級蟠桃
王母娘娘獲得了蟠桃
生長出...
高級蟠桃被孫悟空偷吃完了
王母娘娘沒有得到蟠桃
生長出...
沒有對應等級的蟠桃
王母娘娘沒有得到蟠桃
也就是說,對於產品生產邏輯的變更,我們只需要修改普通工廠模式的核心邏輯類——工廠類就可以了。
我們現在再假設另外一種情況,蟠桃園經過神仙們多年的精心培育,出現了新的品種——超高級蟠桃SuperHighLevelFlatPeach,我們如何改變現有代碼,去體現這個變更呢?也非常方便,只需要在FlatPeach體系下增加這個新的蟠桃,然後再修改一下蟠桃園類生產對應蟠桃的邏輯就可以了:
package com.tirion.design.simple.factory; public class SuperHighLevelFlatPeach implements FlatPeach { SuperHighLevelFlatPeach(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("超高級蟠桃"); } @Override public void printCycleTime() { System.out.println("一萬年一熟"); } }
package com.tirion.design.simple.factory; public class FlatPeachGarden { public static FlatPeach produce(String level) { System.out.println("生長出..."); if ("low".equals(level)) { return new LowLevelFlatPeach(); } else if ("middle".equals(level)) { return new MiddleLevelFlatPeach(); } else if ("high".equals(level)) { return new HighLevelFlatPeach(); } else if ("super high".equals(level)) { return new SuperHighLevelFlatPeach(); } else { System.out.println("沒有對應等級的蟠桃"); return null; } } }
變更後代碼的執行結果如下:
生長出...
三千年一熟
低級蟠桃
王母娘娘獲得了蟠桃
生長出...
六千年一熟
中級蟠桃
王母娘娘獲得了蟠桃
生長出...
九千年一熟
高級蟠桃
王母娘娘獲得了蟠桃
生長出...
一萬年一熟
超高級蟠桃
王母娘娘獲得了蟠桃
可以看到,一萬年一熟的超高級蟠桃比較容易地融入了原有的代碼結構。但是這裡違反了開閉原則,每次對蟠桃種類進行擴展都需要修改蟠桃園類,這一點很不方便。
以上的這些擴展均不用修改消費者的代碼,說明這些代碼的擴展對消費者來說是透明的,這一點在很多設計模式中都非常重要。
普通工廠模式的缺點也很明顯,如果蟠桃園裡的蟠桃種類非常多且經常調整的話,我們就要經常去修改蟠桃園生產蟠桃的方法,而且這個方法本身會非常複雜,效率也會非常低下。而且如果哪一天,孫悟空將這個蟠桃園搗毀了,工廠類無法繼續正常運作,那麼整個體系就完全癱瘓了,這一點非常不安全。同時它違反了單一職責原則,蟠桃園既要負責管理生產蟠桃的邏輯判斷,又要負責蟠桃實例的創建。
為瞭解決這些問題,我們將會引入相對更加高級的工廠模式,請繼續閱讀悟空模式-java-工廠方法模式,這裡對普通方法模式的介紹就到這裡,你可以將它記憶為蟠桃園模式。
如果你認為文章中哪裡有錯誤或者不足的地方,歡迎在評論區指出,也希望這篇文章對你學習java設計模式能夠有所幫助。轉載請註明,謝謝。