上一篇介紹簡單工廠模式
的時候提到它對開閉原則
支持的不夠,因為如果有新的產(chǎn)品加入到系統(tǒng)中去繁疤,就需要修改工廠類,就違反了開閉原則
了躁染,這次介紹的工廠方法模式在保持簡單工廠模式優(yōu)點的前提下架忌,不僅滿足了開閉原則,關(guān)鍵在于它的多態(tài)性饰恕。
開閉原則(Open Close Principle):就是說**對擴展開放井仰,對修改關(guān)閉 ** 。在程序需要進行擴展的時候雹嗦,不能去修改原有的代碼合是,而是要擴展原有的代碼,實現(xiàn)一個熱插拔的效果泊藕。為了使程序的擴展性好难礼,易于維護和升級。想要達到這樣的效果蛾茉,我們需要使用接口和抽象類等。
概念
工廠方法模式(Factory Method Pattern):定義一個用于創(chuàng)建對象的接口吝岭,讓子類決定將哪一個類實例化吧寺。工廠方法模式讓一個類的實例化延遲到其子類稚机。工廠方法模式又簡稱工廠模式(Factory Pattern),有可稱作虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)赖条。工廠方法模式是一種類創(chuàng)建型模式。
作用
在工廠方法模式中碱茁,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的產(chǎn)品對象,而是針對不同的產(chǎn)品提供不同的工廠墓贿,系統(tǒng)提供一個與產(chǎn)品等級結(jié)構(gòu)對應(yīng)的工廠等級結(jié)構(gòu)蜓氨。
實現(xiàn)方式
工廠方法模式的結(jié)構(gòu)圖如下:
從上圖可以看出穴吹,工廠方法模式涉及到抽象工廠角色、具體工廠角色港令、抽象產(chǎn)品角色以及具體產(chǎn)品角色等四個角色:
- 抽象工廠角色:擔任這個角色是工廠方法模式的核心,它是與應(yīng)用程序無關(guān)的缠借。任何在模式中創(chuàng)建對象的工廠類必須實現(xiàn)這個接口泼返。
- 具體工廠角色:擔任這個角色的是實現(xiàn)了抽象工廠接口的具體Java類姨拥,具體工廠角色含有與應(yīng)用密切相關(guān)的邏輯,并且受到應(yīng)用程序的調(diào)用以創(chuàng)建產(chǎn)品對象柴罐。
- 抽象產(chǎn)品角色:工廠方法模式所創(chuàng)建的對象的超類型憨奸,也就是產(chǎn)品對象的共同父類或共同擁有的接口。
- 具體產(chǎn)品角色:這個角色實現(xiàn)了抽象產(chǎn)品角色所申明的接口似芝。工廠方法模式所創(chuàng)建的每一個對象都是某個具體產(chǎn)品角色的實例板甘。
結(jié)合披薩系統(tǒng),就是之前廚師(工廠類)負責所有的烤披薩任務(wù)寞奸,太累了。于是招了兩個廚師分別負責烤GreekPizza
披薩和ChesePizza
披薩枪萄,之前的廚師升級為廚師長(抽象工廠類)瓷翻,負責教那兩位廚師(具體工廠類)烤披薩,自己則不用親自動手烤披薩了逻悠。
附上完整的類圖:
下面是抽象產(chǎn)品的角色Pizza的源代碼:
public abstract class Pizza{
public abstract void prepare();
public abstract void bake();
public abstract void cut();
}
下面是具體角色CheesePizza的源代碼:
public class CheesePizza extends Pizza{
public void prepare(){
System.out.pringln("準備CheesePizza");
}
public void bake(){
System.out.pringln("準備CheesePizza");
}
public void cut(){
System.out.pringln("準備CheesePizza");
}
public void box(){
System.out.pringln("準備CheesePizza");
}
}
下面是具體角色GreekPizza的源代碼:
public class GreekPizza extends Pizza{
public void prepare(){
System.out.pringln("準備GreekPizza");
}
public void bake(){
System.out.pringln("準備GreekPizza");
}
public void cut(){
System.out.pringln("準備GreekPizza");
}
public void box(){
System.out.pringln("準備GreekPizza");
}
}
下面是抽象工廠角色PizzaFactory的代碼单旁,這個角色是使用一個Java接口實現(xiàn)饥伊,它聲明了一個工廠方法,要求所有的具體工廠角色實現(xiàn)這個工廠方法:
public interface PizzaFactory{
//工廠方法
public Pizza createPizza();
}
下面是具體工廠角色CheesePizzaFactory的代碼愉豺,這個角色實現(xiàn)了抽象工廠角色PizzaFactory所聲明的工廠方法:
public class CheesePizzaFactory implements PizzaFactory{
@Override
public Pizza createPizza(){
return new CheesePizza();
}
}
下面是具體工廠角色GreekPizzaFactory的代碼茫因,這個角色實現(xiàn)了抽象工廠角色PizzaFactory所聲明的工廠方法:
public class GreekPizzaFactory implements PizzaFactory{
@Override
public Pizza createPizza(){
return new GreekPizza();
}
}
下面是客戶端角色的源代碼:
public class OrderPizaa{
public static void main(String[] args){
//創(chuàng)建CheesePizzaFactory--具體工廠類
//可以通過反射和配置文件來獲取和存儲具體工廠類的類名冻押,更換新的具體工廠時無須修改源代碼,系統(tǒng)擴展更為方便
PizzaFactory factory = new CheesePizzaFactory();
Pizza pizza = factory.createPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
//創(chuàng)建GreekPizzaFactory()--具體工廠類
pizza = factory.createPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}
結(jié)果演示:
準備CheesePizza
正在烤CheesePizza
正在切CheesePizza
正在打包CheesePizza
準備GreekPizza
正在烤GreekPizza
正在切GreekPizza
正在打包GreekPizza
這里使用工廠方法模式的要點:
工廠方法創(chuàng)建對象:
- 工廠方法不一定每一次都返回一個新的對象括袒,但是它所返回的對象一定是它
自己創(chuàng)建
的稿茉。
工廠方法返回的類型:
- 注意:工廠方法返回的應(yīng)當是
抽象類型
,而不是具體類型恃慧,只有這樣才能保證針對產(chǎn)品的多態(tài)性米苹。
工廠等級結(jié)構(gòu):
- 工廠對象應(yīng)當有一個抽象的超類型。就是說良瞧,應(yīng)當有數(shù)個具體工廠類作為一個抽象超類型的具體子類存在于工廠等級結(jié)構(gòu)中。如果等級結(jié)構(gòu)中只有一個具體工廠類的話褥蚯,那么抽象工廠角色也可以省略赞庶,這時候,工廠方法模式就發(fā)生了退化歧强,這一退化表現(xiàn)為針對工廠角色的多態(tài)性的喪失摊册。
工廠方法模式的優(yōu)缺點
優(yōu)點:
- 工廠方法模式跟簡單工廠模式在結(jié)構(gòu)上不同是很明顯的,工廠方法模式的核心是一個抽象工廠類茅特,而簡單工廠模式的核心在一個具體類。顯而易見妒峦,工廠方法模式這種結(jié)構(gòu)更好擴展兵睛。
- 如果系統(tǒng)需要加入一個新的產(chǎn)品,那么所需要的就是想系統(tǒng)中加入這個產(chǎn)品類以及它所對應(yīng)的工廠類累盗,沒有必要修改客戶端突琳,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色符相。對于增加新的產(chǎn)品類而言,這個系統(tǒng)完全支持開閉原則镜豹。
應(yīng)用場景
不管是簡單工廠模式蓝牲,工廠方法模式還是抽象工廠模式,他們具有類似的特性例衍,所以他們的適用場景也是類似的已卸。
? 首先累澡,作為一種創(chuàng)建類模式般贼,在任何需要生成復(fù)雜對象的地方,都可以使用工廠方法模式哼蛆。有一點需要注意的地方就是復(fù)雜對象適合使用工廠模式腮介,而簡單對象,特別是只需要通過new就可以完成創(chuàng)建的對象萤厅,無需使用工廠模式惕味。如果使用工廠模式,就需要引入一個工廠類名挥,會增加系統(tǒng)的復(fù)雜度禀倔。
? 其次,工廠模式是一種典型的解耦模式救湖,迪米特法則在工廠模式中表現(xiàn)的尤為明顯鞋既。假如調(diào)用者自己組裝產(chǎn)品需要增加依賴關(guān)系時,可以考慮使用工廠模式邑闺。將會大大降低對象之間的耦合度陡舅。
? 再次,由于工廠模式是依靠抽象架構(gòu)的灾炭,它把實例化產(chǎn)品的任務(wù)交由實現(xiàn)類完成,擴展性比較好咆贬。也就是說,當需要系統(tǒng)有比較好的擴展性時皱蹦,可以考慮工廠模式眷蜈,不同的產(chǎn)品用不同的實現(xiàn)工廠來組裝酌儒。
迪米特法則(Law of Demeter):一個軟件實體應(yīng)當盡可能少地與其他實體發(fā)生相互作用。
在將迪米特法則運用到系統(tǒng)設(shè)計中時忌怎,要注意下面的幾點:
- 在類的劃分中榴啸,應(yīng)當盡量創(chuàng)建松耦合的類,類之間的耦合度越低鸥印,就月有利于復(fù)用库说,一個處在松耦合的類一旦被修改,不會對關(guān)聯(lián)的類造成太大的波及潜的。
- 在類的結(jié)構(gòu)設(shè)計上夏块,每一個類都應(yīng)當盡量降低其成員變量和成員函數(shù)的訪問權(quán)限。
- 在類的設(shè)計上,只要有可能借跪,一個類型應(yīng)當設(shè)計成不變類。
- 在對其他類的引用上歇由,一個對象對其他對象的引用應(yīng)當降到最低。