【一朝,王母娘娘設宴,大開寶閣,瑤池中做蟠桃勝會】 有一天,王母娘娘要在瑤池辦party,就需要準備大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方將、二十八宿、四大天王、十二元辰、五方五老、普天星相、河漢群神等等,不同等級的神仙在宴會中吃的東西也不一樣。 為了方便管理,我們把神仙分為低級神 ...
【一朝,王母娘娘設宴,大開寶閣,瑤池中做蟠桃勝會】
有一天,王母娘娘要在瑤池辦party,就需要準備大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方將、二十八宿、四大天王、十二元辰、五方五老、普天星相、河漢群神等等,不同等級的神仙在宴會中吃的東西也不一樣。
為了方便管理,我們把神仙分為低級神仙、中級神仙和高級神仙,不同等級的神仙將領取到對應等級的食物,所以就有了低級神仙食物、中級神仙食物和高級神仙食物。
在前面的悟空模式-java-普通工廠模式和悟空模式-java-工廠方法模式中都介紹了低級蟠桃(三千年)、中級蟠桃(六千年)和高級蟠桃(九千年),雖然是蟠桃盛會,但也總不能光吃蟠桃,所以由兜率宮拿出了一批仙丹,分為低級仙丹(煉三三得九天)、中級仙丹(煉七七四十九天)和高級仙丹(煉九九八十一天)。
以上,就是我們本次演示抽象工廠模式所需要的產品元素。
在前面我們說過,當產品越來越多,會使得工廠越來越難管理,要麼工廠的數量越來越多,要麼工廠本身越來越複雜,所以,這裡介紹了抽象工廠模式,用於產生較為複雜的產品結構下的工廠,它與工廠方法最基本的區別是抽象工廠模式能夠創建不同種類的產品,也就能夠更加方便地基於抽象的概念管理一大堆複雜的產品對象。
首先我們介紹兩個概念:產品族與產品等級。
所謂產品族,就是由功能相關聯的不同種類產品組成的家族,比如我們最終所需要的低級神仙食物,它是由低級蟠桃與低級仙丹組成的。而產品等級就是對於某一種類的產品,內部劃分的等級結構,如蟠桃內部被劃分為低級、中級與高級,產品等級是面向同一種類的產品的內部區別描述。
在一開始,我們需要創建一個抽象工廠,這個抽象工廠中描述了每個具體工廠需要提供哪些實現。然後針對每一個產品族創建一個工廠,用於統一創建不同類型的產品。類圖如下:
從圖中可以看到,不同等級的產品交給了不同的工廠去創建,用戶只需要調用自己的目標產品族對應的工廠,獲取最終的產品族即可,至於這個產品系列內部結構如何變化,用戶並不需要關心。接下來是具體的實現:
蟠桃
package com.tirion.design.abstraction.factory; public interface FlatPeach { void printLevel(); void printCycleTime(); }
低級蟠桃
package com.tirion.design.abstraction.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.abstraction.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.abstraction.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.abstraction.factory; public interface Elixir { void printLevel(); void printCycleTime(); }
低級仙丹
package com.tirion.design.abstraction.factory; public class LowLevelElixir implements Elixir { LowLevelElixir(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("低級仙丹"); } @Override public void printCycleTime() { System.out.println("煉三三得九天"); } }
中級仙丹
package com.tirion.design.abstraction.factory; public class MiddleLevelElixir implements Elixir { MiddleLevelElixir(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("中級仙丹"); } @Override public void printCycleTime() { System.out.println("煉七七四十九天"); } }
高級仙丹
package com.tirion.design.abstraction.factory; public class HighLevelElixir implements Elixir { HighLevelElixir(){ printCycleTime(); printLevel(); } @Override public void printLevel() { System.out.println("高級仙丹"); } @Override public void printCycleTime() { System.out.println("煉九九八十一天"); } }
抽象工廠-神仙食物工廠
package com.tirion.design.abstraction.factory; public interface XianFoodFactory { FlatPeach prepareFlatPeach(); Elixir prepareElixir(); }
低級神仙食物工廠
package com.tirion.design.abstraction.factory; public class LowLevelXianFoodFactory implements XianFoodFactory { @Override public FlatPeach prepareFlatPeach() { return new LowLevelFlatPeach(); } @Override public Elixir prepareElixir() { return new LowLevelElixir(); } }
中級神仙食物工廠
package com.tirion.design.abstraction.factory; public class MiddleLevelXianFoodFactory implements XianFoodFactory { @Override public FlatPeach prepareFlatPeach() { return new MiddleLevelFlatPeach(); } @Override public Elixir prepareElixir() { return new MiddleLevelElixir(); } }
高級神仙食物工廠
package com.tirion.design.abstraction.factory; public class HighLevelXianFoodFactory implements XianFoodFactory { @Override public FlatPeach prepareFlatPeach() { return new HighLevelFlatPeach(); } @Override public Elixir prepareElixir() { return new HighLevelElixir(); } }
王母娘娘-調用者
package com.tirion.design.abstraction.factory; public class TheQueenMother { public static void prepareXianFood(XianFoodFactory xianFoodFactory) { xianFoodFactory.prepareFlatPeach(); xianFoodFactory.prepareElixir(); } public static void main(String[] args) { System.out.println("準備低級神仙食物..."); TheQueenMother.prepareXianFood(new LowLevelXianFoodFactory()); System.out.println("準備中級神仙食物..."); TheQueenMother.prepareXianFood(new MiddleLevelXianFoodFactory()); System.out.println("準備高級神仙食物..."); TheQueenMother.prepareXianFood(new HighLevelXianFoodFactory()); } }
代碼執行結果
準備低級神仙食物...
三千年一熟
低級蟠桃
煉三三得九天
低級仙丹
準備中級神仙食物...
六千年一熟
中級蟠桃
煉七七四十九天
中級仙丹
準備高級神仙食物...
九千年一熟
高級蟠桃
煉九九八十一天
高級仙丹
使用了抽象工廠模式之後,在面對複雜的宴會菜單對象時,王母娘娘不需要關心天宮的御廚如何搭配食物,只需要下達命令要求御廚準備不同等級的食物套餐就可以了。
每個具體工廠只需要創建自己負責的產品,這符合單一職責原則。
具體工廠返回的產品是產品的抽象而不是具體,所以符合依賴導致原則。
關於開閉原則,抽象工廠模式是一個比較典型的例子。
我們在使用中可以發現,如果要添加一個新的產品族,比如王母娘娘專享食物套餐,套餐內容是高級蟠桃,而並不需要吃仙丹(王母娘娘吃仙丹已經沒啥用了),那麼我們只需要增加一個TheQueenMotherFoodFactory,然後在內部添加具體的實現即可,並不需要更改其他任何類,很完美地符合了開閉原則。
王母娘娘食物工廠
package com.tirion.design.abstraction.factory; public class TheQueenMotherFoodFactory implements XianFoodFactory { @Override public FlatPeach prepareFlatPeach() { return new HighLevelFlatPeach(); } @Override public Elixir prepareElixir() { return null; } }
但是如果某一天,鎮元大仙上供了一批人參果,王母娘娘一高興,把人參果也作為宴會的一道主菜,那麼就麻煩了:不僅僅抽象工廠XianFoodFactory要增加人參果的介面,它的所有實現都要增加相應的介面實現,整個體系才能繼續運轉下去。這時候,抽象工廠模式又不符合開閉原則了。
根據以上描述我們可以得出,對於抽象工廠模式,增加產品族符合開閉原則,增加產品種類則不符合開閉原則,也就是說抽象工廠模式具備開閉原則的傾斜性。
註意:抽象工廠模式並不是比工廠方法模式更加高級的模式,而是為了適應不同的業務變化情況而做出的不同應對,繼而產生的不同解決方案而已。
抽象工廠模式的使用情景:
1.系統中存在多個產品族,用戶只關心產品族,也就是只關心最終結果
2.屬於同一產品族的產品相互之間具有關聯關係,它們是被組合在一起使用的
抽象工廠模式遵循的設計原則:
1.依賴倒置原則(客戶端依賴的是產品抽象而不是具體產品)
2.迪米特法則
3.里氏替換原則
4.介面隔離原則(使用了多個相互隔離的介面,降低了耦合度)
5.單一職責原則(每個工廠只要負責創建自己對應產品族的產品)
6.開閉原則(具有傾斜性,支持新增產品族,但不支持新增產品類型)
關於抽象工廠模式的介紹就到這裡,你可以將它記憶為蟠桃宴會模式。
如果你認為文章中哪裡有錯誤或者不足的地方,歡迎在評論區指出,也希望這篇文章對你學習java設計模式能夠有所幫助。轉載請註明,謝謝。
更多設計模式的介紹請到悟空模式-java設計模式中查看。