上一篇介紹簡單工廠模式的時候提到它對開閉原則支持的不夠,因為如果有新的產品加入到系統中去,就需要修改工廠類,就違反了開閉原則了,這次介紹的工廠方法模式在保持簡單工廠模式優點的前提下,還滿足了開閉原則,關鍵在于它的多態性。
一、工廠方法模式概念
工廠方法模式是類的創建模式,又叫做虛擬構造子(Cirtual Constructor)模式或者多態工廠(Polymorphic Factory)模式。
工廠方法模式的用意是定義一個創建產品對象的工廠接口,將實際創建工作推遲到子類中。
首先,在工廠方法模式中,核心的工廠類不再負責所有產品的創建,而是將具體創建的工作交給子類去做。這個核心類則搖身一變,成為了一個抽象工廠角色,僅負責給出具體工廠子類必須實現的接口,而不接觸哪一個產品類應當被實例化這種細節。
這種進一步抽象化的結果,使這種工廠方法模式可以用來予許系統在不修改具體工廠角色的情況下引進新的產品,也就遵循了開閉原則。
二、工廠方法模式的結構
工廠方法模式的結構圖如下:
從上圖可以看出, 工廠方法模式涉及到抽象工廠角色,具體工廠角色,抽象產品角色以及具體產品角色等四個角色:
- 抽象工廠角色:擔任這個角色的是工廠方法模式的核心,它是與應用程序無關的。任何在模式中創建對象的工廠類必須實現這個接口。
- 具體工廠角色:擔任這個角色的是實現了抽象工廠接口的具體Java類,具體工廠角色含有與應用密切相關的邏輯,并且受到應用程序的調用以創建產品對象。
- 抽象產品角色:工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
- 具體產品角色:這個角色實現了抽象產品角色所申明的接口。工廠方法模式所創建的每一個對象都是某個具體產品角色的實例。
結合披薩系統,用白話文來說就是之前廚師(工廠類)負責所有的烤披薩任務,太累了。于是招了兩個廚師分別負責烤 GreekPizza
披薩和 CheesePizza
披薩,之前的廚師升級為廚師長(抽象工廠類),負責教那兩位廚師(具體工廠類)烤披薩,自己則不用親自動手烤披薩了。
附上代碼前先來看看完整的類圖:
三、代碼示例
下面是抽象產品的角色Pizza的源代碼:
public abstract class Pizza { public abstract void prepare(); public abstract void bake(); public abstract void cut(); public abstract void box(); }
下面是具體產品角色CheesePizza的源代碼:
public class CheesePizza extends Pizza{ public void prepare(){ System.out.println("準備CheesePizza~"); } public void bake(){ System.out.println("正在烤CheesePizza~"); } public void cut(){ System.out.println("正在切CheesePizza~"); } public void box(){ System.out.println("正在打包CheesePizza~"); } }
下面是具體產品角色GreekPizza的源代碼:
public class GreekPizza extends Pizza{ public void prepare(){ System.out.println("準備GreekPizza~"); } public void bake(){ System.out.println("正在烤GreekPizza~"); } public void cut(){ System.out.println("正在切GreekPizza~"); } public void box(){ System.out.println("正在打包GreekPizza~"); } }
下面是抽象工廠角色PizzaFactory的代碼,這個角色是使用一個java接口實現,它聲明了一個工廠方法,要求所有的具體工廠角色實現這個工廠方法:
public interface PizzaFactory { /** * 工廠方法 * @return */ public Pizza createPizza(); }
下面是具體工廠角色CheesePizzaFactory的代碼,這個角色現實了抽象工廠角色PizzaFactory所聲明的工廠方法:
public class CheesePizzaFactory implements PizzaFactory{ @Override public Pizza createPizza() { return new CheesePizza(); } }
下面是具體工廠角色GreekPizzaFactory的代碼,這個角色現實了抽象工廠角色PizzaFactory所聲明的工廠方法:
public class GreekPizzaFactory implements PizzaFactory{ @Override public Pizza createPizza() { return new GreekPizza(); } }
下面是客戶端角色的源代碼:
public class OrderPizza { public static void main(String[] args){ PizzaFactory factory=new CheesePizzaFactory(); Pizza pizza=factory.createPizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); factory=new GreekPizzaFactory(); pizza=factory.createPizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } }
結果演示:
準備CheesePizza~ 正在烤CheesePizza~ 正在切CheesePizza~ 正在打包CheesePizza~ 準備GreekPizza~ 正在烤GreekPizza~ 正在切GreekPizza~ 正在打包GreekPizza~
這里使用工廠方法模式的注意點:
工廠方法創建對象:
工廠方法不一定每一次都返還一個新的對象,但是它所返還的對象一定是它自己創建
的。
工廠方法返還的類型:
注意:工廠方法返還的應當是抽象類型
,而不是具體類型,只有這樣才能保證針對產品的多態性。當工廠方法模式發生上面的退化時,就不再是工廠方法模式了。
工廠等級結構:
工廠對象應當有一個抽象的超類型。換言之,應當有數個具體工廠類作為一個抽象超類型的具體子類存在于工廠等級結構中。如果等級結構中只有一個具體工程類的話,那么抽象工廠角色也可以省略,這時候,工廠方法模式就發生了退化,這一退化表現為針對工廠角色的多態性的喪失。
四、總結
工廠方法模式和簡單工廠模式比較:
工廠方法模式跟簡單工廠模式在結構上的不同是很明顯的,工廠方法模式的核心是一個抽象工廠類,而簡單工廠模式的核心在一個具體類。顯而易見工廠方法模式這種結構更好擴展,權力下發,分布式比集中式更具優勢。
如果系統需要加入一個新的產品,那么所需要的就是向系統中加入一個這個產品類以及它所對應的工廠類。沒有必要修改客戶端,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色。對于增加新的產品類而言,這個系統完全支持開閉原則。
文章列表