【卻說那七衣仙女自受了大聖的定身法術,一周天方能解脫,各提花籃,回奏王母說道:“齊天大聖使術法困住我等,故此來遲。”王母問道:“汝等摘了多少蟠桃?”仙女道:“只有兩籃小桃,三籃中桃。至後面,大桃半個也無,想都是大聖偷吃了。及正尋間,不期大聖走將出來,行凶拷打,又問設宴請誰。我等把上會事說了一遍,他就 ...
【卻說那七衣仙女自受了大聖的定身法術,一周天方能解脫,各提花籃,回奏王母說道:“齊天大聖使術法困住我等,故此來遲。”王母問道:“汝等摘了多少蟠桃?”仙女道:“只有兩籃小桃,三籃中桃。至後面,大桃半個也無,想都是大聖偷吃了。及正尋間,不期大聖走將出來,行凶拷打,又問設宴請誰。我等把上會事說了一遍,他就定住我等,不知去向。直到如今,才得醒解回來。”王母聞言,即去見玉帝,備陳前事。】
在《西游記》第五回《亂蟠桃大聖偷丹 反天宮諸神捉怪》里,悟空將奉王母之命前去蟠桃園摘桃的七衣仙女定住,隨即自己偷吃仙桃的事情也因而敗露了。
在悟空模式-java-普通工廠模式中,我們舉了王母娘娘(消費者)從蟠桃園(普通工廠類)中獲取蟠桃(產品)的例子來說明普通方法模式,我們發現蟠桃園這個類是普通方法模式的核心類,一旦出現問題,整個設計體系就崩潰了。果不其然,齊天大聖很快就搗亂了,當他把七衣仙女定住的時候,蟠桃園就停止工作,王母娘娘就沒有辦法獲取到蟠桃了,直到過了一周天,蟠桃園恢復運行,王母才拿到幾籃桃子。
那麼接下來我們就嘗試使用工廠方法模式來降低蟠桃系統的風險,主要的改動就是將原本作為核心的蟠桃園類修改為以抽象蟠桃園作為核心,蟠桃的產出交由各個具體的蟠桃園負責,這樣某一個蟠桃園出現問題,不影響其他蟠桃園的正常運行:
蟠桃
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.factory.method; public abstract class FlatPeachGarden { public abstract FlatPeach produce(); }
低級蟠桃園
package com.tirion.design.factory.method; public class LowLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { return new LowLevelFlatPeach(); } }
中級蟠桃園
package com.tirion.design.factory.method; public class MiddleLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { return new MiddleLevelFlatPeach(); } }
高級蟠桃園
package com.tirion.design.factory.method; public class HighLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { return new HighLevelFlatPeach(); } }
王母娘娘
package com.tirion.design.factory.method; public class TheQueenMother { public static FlatPeach getLowLevelFlatPeach() { FlatPeachGarden garden = new LowLevelFlatPeachGarden(); FlatPeach flatPeach = garden.produce(); if (flatPeach == null) { System.out.println("王母娘娘沒有得到蟠桃"); } else { System.out.println("王母娘娘獲得了蟠桃"); } return flatPeach; } public static FlatPeach getMiddleLevelFlatPeach() { FlatPeachGarden garden = new MiddleLevelFlatPeachGarden(); FlatPeach flatPeach = garden.produce(); if (flatPeach == null) { System.out.println("王母娘娘沒有得到蟠桃"); } else { System.out.println("王母娘娘獲得了蟠桃"); } return flatPeach; } public static FlatPeach getHighLevelFlatPeach() { FlatPeachGarden garden = new HighLevelFlatPeachGarden(); FlatPeach flatPeach = garden.produce(); if (flatPeach == null) { System.out.println("王母娘娘沒有得到蟠桃"); } else { System.out.println("王母娘娘獲得了蟠桃"); } return flatPeach; } public static void main(String[] args) { TheQueenMother.getLowLevelFlatPeach(); TheQueenMother.getMiddleLevelFlatPeach(); TheQueenMother.getHighLevelFlatPeach(); } }
在上面的代碼中,我們將三種蟠桃分別交給三個不同類別的蟠桃園進行管理,每個蟠桃園負責生產某一種類的蟠桃,這樣就把不同蟠桃的管理拆分開來,不再集中於一個蟠桃園,降低了系統的耦合風險。代碼執行結果如下:
找到對應等級的蟠桃園
三千年一熟
低級蟠桃
王母娘娘獲得了蟠桃
找到對應等級的蟠桃園
六千年一熟
中級蟠桃
王母娘娘獲得了蟠桃
找到對應等級的蟠桃園
九千年一熟
高級蟠桃
王母娘娘獲得了蟠桃
王母娘娘想要哪個種類的蟠桃,就派仙女去對應的蟠桃園去採摘,這就是工廠方法模式的運作方式,上例的類圖如下:
現在我們將工廠方法模式與普通方法模式進行比較,看看工廠方法模式在面對一些問題時會有什麼樣的表現:
現在蟠桃園出現了同樣的情況,悟空把高級蟠桃園裡的桃子全部偷吃光了,又把中間蟠桃園的仙女用定身法術定住了,我們如何處理這樣的變化呢?方法如下:
修改高級蟠桃園類和中級蟠桃園類
package com.tirion.design.factory.method; public class HighLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { System.out.println("高級蟠桃被齊天大聖偷吃光了!"); return null; // return new HighLevelFlatPeach(); } }
package com.tirion.design.factory.method; public class MiddleLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { System.out.println("齊天大聖把中級蟠桃園的仙女定住了,沒辦法取蟠桃!"); return null; // return new MiddleLevelFlatPeach(); } }
其他類不變,再來看代碼的允許結果:
找到對應等級的蟠桃園 三千年一熟 低級蟠桃 王母娘娘獲得了蟠桃 找到對應等級的蟠桃園 齊天大聖把中級蟠桃園的仙女定住了,沒辦法取蟠桃! 王母娘娘沒有得到蟠桃 找到對應等級的蟠桃園 高級蟠桃被齊天大聖偷吃光了! 王母娘娘沒有得到蟠桃
也就是說,哪個具體的工廠類出現了變化,我們就修改對應的工廠類就可以了,這樣代碼修改不會影響其他沒有發生變化的業務代碼邏輯,符合“單一職責原則”。產品的選擇方案與工廠本身分離開來,工廠只要負責創建產品實例就可以了。
我們再來看另外一種情況,高級蟠桃被悟空吃掉了之後,也許是被齊天大聖的靈氣所激發,部分果核後來居然生長出了一種新的蟠桃樹,一萬年一熟,我們叫它超高級蟠桃。下麵我們將對工廠方法模式的蟠桃園體系進行調整,以適應蟠桃品種的變化:
超高級蟠桃
package com.tirion.design.factory.method; 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.factory.method; public class SuperHighLevelFlatPeachGarden extends FlatPeachGarden { @Override public FlatPeach produce() { return new SuperHighLevelFlatPeach(); } }
這樣,我們就把這種新的蟠桃品種加入進來了。王母娘娘暫時還不知道有了新的蟠桃,哪天她知道了,就派人去超高級蟠桃園去採摘就可以了。
從上面可以看出,增加一個新的蟠桃品種只需要增加一個新的產品類(超高級蟠桃)和一個新的產品工廠(超高級蟠桃園),而不必更改原有體系中任何一個類的代碼,這樣就符合了“開閉原則”。
所以說,工廠方法模式是普通工廠模式為了適應更多的未來變化而衍生出來的更高級的工廠模式,它解決了一些普通工廠模式違背的設計原則問題,即單一職責原則和開閉原則。
但是,工廠方法模式也有它的缺陷,那就是隨著產品越來越多,每個產品都需要新建一個產品類和對應的工廠類,這樣最終會導致類非常多。消費者也很難管理這些類。以上面的例子來說,就是最終蟠桃園裡有好幾十種蟠桃,王母娘娘也搞不清楚到底要哪些蟠桃,派仙女去哪些蟠桃園去採摘,最終引發體系混亂,代碼修改難度加大,風險也隨之上升。
為瞭解決這個問題,我們引入了悟空模式-java-抽象工廠模式,關於工廠方法模式的介紹就到這裡,你可以將它記憶為多蟠桃園模式。
如果你認為文章中哪裡有錯誤或者不足的地方,歡迎在評論區指出,也希望這篇文章對你學習java設計模式能夠有所幫助。轉載請註明,謝謝。