设计模式(3):抽象工厂模式(Abstract Factory Pattern)
1.繼續(xù)工廠方法模式
在工廠方法模式中,介紹了一個工廠類創(chuàng)建一中產(chǎn)品,所有的工廠類都是基于接口實現(xiàn)的,所有的產(chǎn)品也是基于接口實現(xiàn)的。這樣當增加新的產(chǎn)品的時候只需要實現(xiàn)新的工廠類和新的產(chǎn)品類即可,滿足了開-閉原則。
但是隨著產(chǎn)品線的復雜,很多產(chǎn)品并不是由一部分構成,而是由多種產(chǎn)品組件構成,每種產(chǎn)品構成一個產(chǎn)品族。比如,以Pizza為例,生產(chǎn)一個Pizza需要面餅和各種醬料(簡化了,實際上需要的更多),只有面餅和醬料都準備好了才能生產(chǎn)一個Pizza。
這樣的話,雖然我們可以繼續(xù)使用工廠方法模式,為每個產(chǎn)品組件創(chuàng)建一個工廠類,但是又顯得臃腫,不如將生產(chǎn)各個組件的工廠類合并為一個工廠類,這個總的工廠類負責生產(chǎn)最終的產(chǎn)品。以Pizza為例,可以設計一個生產(chǎn)Pizza的類,在這個類里面,會生產(chǎn)面餅和醬料。這就是抽象工廠模式(Abstract Factory Pattern)。
抽象工廠模式的簡單圖如下:
在上面的圖中,左邊表示工廠的等級結構,右邊表示產(chǎn)品的等級結構(一共有兩種產(chǎn)品等級結構)。
抽象工廠模式提供一個接口,使得客戶端在不用指定產(chǎn)品的具體類型的情況下創(chuàng)建多個產(chǎn)品族中的產(chǎn)品對象。
2.抽象工廠模式的結構
通過上面的介紹,可以知道抽象工廠模式是工廠方法模式的進一步推廣。下圖就是抽象工廠模式的結構:
上面就是抽象工廠模式的結構圖。左邊是工廠的等級結構,右邊是產(chǎn)品的等級結構。可以看出,這個抽象工廠生產(chǎn)的產(chǎn)品包括ProductA和ProductB,但是兩個組件的種類可以不同。這樣就可以相互組合。
抽象工廠模式涉及到的角色和工廠方法模式里面的角色是一樣的,也是抽象工廠、具體工廠、抽象產(chǎn)品和具體產(chǎn)品,這里就不細說了。
下面是使用抽象工廠模式的代碼框架:
(1)抽象工廠
(2)具體工廠
這里給出兩個具體工廠,代表兩種產(chǎn)品(組合了不同子產(chǎn)品)。
(3)抽象產(chǎn)品
有兩種產(chǎn)品:
(4)具體產(chǎn)品
public class ProductA1 implements ProductA { }public class ProductA2 implements ProductA { }public class ProductB1 implements ProductB { }public class ProductB2 implements ProductB { }3.舉個例子
繼續(xù)工廠方法模式中的Pizza店的例子。這里,Pizza店并不僅僅只是制造Pizza,也需要制造Pizza的原料。之前我們開了兩家Pizza店,New York風味的和Chicago風味的。兩家Pizza店都提供相同的產(chǎn)品族,比如芝士披薩,素食披薩,蛤蜊披薩和意式臘腸披薩等。因為兩家店的風味不同,每種Pizza的原料也有所不同。
首先,重新定義一下抽象工廠(Pizza店):
由于原料有很多,所以我們需要一個制造原料的工廠:
//原料工廠是一個接口,每個原料都有一個對應的方法創(chuàng)建該原料 public interface PizzaIngredientFactory {public Dough createDough();public Sauce createSauce();public Veggies[] createVeggies();public Pepperoni createPepperoni();public Clams createClam(); }現(xiàn)在我們要做的就是,為每一個區(qū)域(比如New York,Chicago)建造一個工廠,這個工廠需要實現(xiàn)PizzaIngredientFactory接口,并實現(xiàn)里面創(chuàng)建原料的方法。
然后,我們需要提供原料類,比如ReggianoCheese、RedPeppers、ThickCrustDough等。這些原料類可以在不同的區(qū)域之間共享。
創(chuàng)建一個New York原料工廠:
工廠已經(jīng)有了,可以開始制作Pizza了。但是和工廠方法模式里的不同,這里的Pizza需要有許多原料,適合使用抽象類,而不是接口:
//一個抽象類,表示抽象產(chǎn)品 public abstract class Pizza {String name;//這些都是Pizza的原料Dough dough;Sauce sauce;Veggies[] veggies;Cheese cheese;Pepperoni pepperoni;Clams clam;//這個方法提前準備原料abstract void prepare();void bake() {System.out.println("Bake for 25 minutes.");}void cut() {System.out.println("Cutting the pizza into diagonal slices.");}void box() {System.out.println("Place pizza in official PizzaStore box.");}void setName(String name) {this.name=name;}String getName() {reutrn name;}public String toString() {//打印Pizza的具體信息} }有了這個抽象Pizza,就可以創(chuàng)建具體的Pizza類了。這里先創(chuàng)建一個芝士披薩:
//這是一個具體類,表示芝士披薩,繼承于Pizza抽象類 public class CheesePizza extends Pizza {//每個具體的Pizza類都需要一個原料工廠,由構造參數(shù)傳進來PizzaIngredientFactory ingredientFactory;public CheesePizza(PizzaIngredientFactory ingredientFactory) {this.ingredientFactory=ingredientFactory;}//這就是prepare方法,在這個方法里,使用原料工廠創(chuàng)建芝士披薩所需的原料void prepare() {System.out.println("Preparing "+name);dough=ingredientFactory.createDough();sauce=ingredientFactory.createSauce();cheese=ingredientFactory.createCheese();} }從這個具體類中我們可以看到,里面使用的都是抽象的。比如原料工廠,是一個接口;使用的原料類,也都是接口。原料的具體化,是通過原料工廠的createXXX()方法完成的。如果需要不同風味的原來,那么提供不同的原料工廠就可以了。
再來一個具體Pizza,蛤蜊披薩:
好了,現(xiàn)在原料工廠有了,具體產(chǎn)品類也有了,開始創(chuàng)建Pizza店吧:
//具體的Pizza店,首先創(chuàng)建一個New York的原料工廠,根據(jù)不同的類型創(chuàng)建不同的Pizza public class NewYorkPizzaStore extends PizzaStore {protected Pizza createPizza(String type) {Pizza pizza=null;PizzaIngredientFactory ingredientFactory=new NewYorkIngredientFactory();if(type.equals("cheese")) {pizza=new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");} else if(type.equals("veggie")) {pizza=new VeggiePizza(ingredientFactory);pizza.setName("New York Style Veggie Pizza");} else if(type.equals("clam")) {pizza=new ClamPizza(ingredientFactory);pizza.setName("New York Style Clam Pizza");} else if(type.equals("pepperoni")) {pizza=new PepperoniPizza(ingredientFactory);pizza.setName("New York Style Pepperoni Pizza");}return pizza;} } //這里只給出了New York的Pizza店,沒有給出Chicago的具體實現(xiàn),不過原理是一樣的當需要訂餐時,這樣就好了:
public class Client {public static void main(String[] args) {PizzaStore nyPizzaStore=new NewYorkPizzaStore();Pizza nyCheesePizza=nyPizzaStore.orderPizza("cheese");//enjoy yourself} }4.和工廠方法模式的異同
工廠方法模式和抽象工廠模式有點相似,它們所需的角色一樣,但是又有很大的不同。下面簡單討論一下:
參考資料:《Java與模式》,閻宏
總結
以上是生活随笔為你收集整理的设计模式(3):抽象工厂模式(Abstract Factory Pattern)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lol诺克萨斯之手怎么买符文啊最后帮我买
- 下一篇: 网络基础一(协议的概念,网络应用程序设计