前面的簡單工廠和工廠方法,咱們用了披薩店生產披薩作了例子,接下來使用生產披薩原料(麪糰、醬料、蔬菜、肉等等)來描述一下抽象工廠。java
建造一個生產原料的工廠,並將原料運送到各家加盟店。加盟店座落在不一樣的區域,紐元的紅醬料和芝加哥的紅醬料是不同的。因此對於紐約和芝加哥,須要準備兩組不一樣的原料。ide
例如,Dough(麪糰)的話,芝加哥喜歡使用ThickCrustDough(厚麪餅),而紐約喜歡使用ThinCrustDough(薄面餅);Sauce(醬料)的話,芝加哥喜歡PlumTomatoSauce(小西紅柿番茄醬),而紐約喜歡MarinaraSauce(海員式沙司,含西紅柿、大蒜、洋蔥等調製成);還有芝士、蛤蜊等原料,類圖以下:函數
package cn.net.bysoft.factory; /** * 生麪糰的抽象類。 * 它是作披薩的一種原料,會由原料的抽象工廠建立。 */ public abstract class Dough { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 紐約風格的薄面餅。 * */ public class ThinCrustDough extends Dough { public ThinCrustDough() { super.setName("薄面餅"); } } /** * 芝加哥風格的厚麪餅。 * */ public class ThickCrustDough extends Dough { public ThickCrustDough() { super.setName("厚麪餅"); } }
/** * 醬汁的抽象類。 * 它是作披薩的一種原料,會由原料的抽象工廠建立。 */ public abstract class Sauce { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 芝加哥風味小西紅柿製做的番茄醬。 * */ public class PlumTomatoSauce extends Sauce { public PlumTomatoSauce() { super.setName("小西紅柿番茄醬"); } } /** * 紐約風味海員式沙司,由西紅柿、大蒜、洋蔥等食材調製成的。 * */ public class MarinaraSauce extends Sauce { public MarinaraSauce() { super.setName("海員式沙司"); } }
/** * 芝士的抽象類。 * 它是作披薩的一種原料,會由原料的抽象工廠建立。 * */ public abstract class Cheese { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 芝加哥風味的馬蘇裏拉奶酪。 * */ public class MozzarellaCheese extends Cheese { public MozzarellaCheese() { super.setName("馬蘇裏拉奶酪"); } } /** * 紐約風味的帕馬森乾酪。 * */ public class ReggianoCheese extends Cheese { public ReggianoCheese() { super.setName("帕馬森乾酪"); } }
/** * 蛤蜊的抽象類。 * 它是作披薩的一種原料,會由原料的抽象工廠建立。 */ public abstract class Clam { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 芝加哥冷凍蛤蜊,因爲芝加哥不靠海,蛤蜊不是新鮮的。 * */ public class FrozenClam extends Clam { public FrozenClam() { super.setName("冷凍蛤蜊"); } } /** * 紐約新鮮蛤蜊,因爲紐約靠海,蛤蜊是新鮮的。 * */ public class FreshClam extends Clam { public FreshClam() { super.setName("新鮮蛤蜊"); } }
/** * 蔬菜的抽象類。 * 它是作披薩的一種原料,會由原料的抽象工廠建立。 */ public abstract class Veggies { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 大蒜。 * */ public class Garlic extends Veggies { public Garlic() { super.setName("大蒜"); } } /** * 洋蔥。 * */ public class Onion extends Veggies { public Onion() { super.setName("洋蔥"); } } /** * 蘑菇。 * */ public class Mushroom extends Veggies { public Mushroom() { super.setName("蘑菇"); } } /** * 紅辣椒。 * */ public class RedPepper extends Veggies { public RedPepper() { super.setName("紅辣椒"); } }
從總體來看,這兩個區域(紐約和芝加哥)組成了原料家族,每一個區域實現了一個完整的原料家族。學習
如今,咱們要建立一個工廠來生成原料,這個工廠將負責建立原料家族中的每一種原料。也就是說,工廠將生產麪糰、醬料、芝士等。this
開始先爲工廠定義一個接口,這個接口負責建立全部的原料:spa
/** * 原料的抽象工廠接口。 * */ public interface PizzaIngredientFactory { /** * 建立生麪糰。 * */ public Dough createDough(); /** * 建立醬料。 * */ public Sauce createSauce(); /** * 建立芝士。 * */ public Cheese createCheese(); /** * 建立蔬菜。 * */ public Veggies[] createVeggies(); /** * 建立蛤蜊。 * */ public Clam createClam(); }
如上面的代碼所示,咱們建立了一個名爲PizzaIngredientFactory的接口,這個接口用於建立一族原料。有面團、醬料、芝士、蔬菜和蛤蜊。接下來,在建立紐約的原料工廠和芝加哥的原料工廠:.net
/** * 紐約披薩店的原料工廠。 * */ public class NYPizzaIngredientFactory implements PizzaIngredientFactory { /** * 建立生麪糰。 * */ public Dough createDough() { return new ThinCrustDough(); } /** * 建立醬料。 * */ public Sauce createSauce() { return new MarinaraSauce(); } /** * 建立芝士。 * */ public Cheese createCheese() { return new ReggianoCheese(); } /** * 建立蔬菜。 * */ public Veggies[] createVeggies() { Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; return veggies; } /** * 建立蛤蜊。 * */ public Clam createClam() { return new FreshClam(); } }
/** * 芝加哥披薩店的原料工廠。 * */ public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory { /** * 建立生麪糰。 * */ public Dough createDough() { return new ThickCrustDough(); } /** * 建立醬料。 * */ public Sauce createSauce() { return new PlumTomatoSauce(); } /** * 建立芝士。 * */ public Cheese createCheese() { return new MozzarellaCheese(); } /** * 建立蔬菜。 * */ public Veggies[] createVeggies() { Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; return veggies; } /** * 建立蛤蜊。 * */ public Clam createClam() { return new FrozenClam(); } }
咱們先建立了名爲NYPizzaIngredientFactory的紐約原料工廠,該工廠生產的原料產品都是紐約風格的。例如,麪糰作成薄面餅、醬料是海員沙司、芝士是帕馬森乾酪、蛤蜊是新鮮蛤蜊、蔬菜有大蒜、洋蔥、蘑菇和紅辣椒。code
接下來又建立了名爲ChicagoPizzaIngredientFactory的芝加哥原料工廠,該工廠生產的原料產品都是芝加哥風格的。例如麪糰作成厚麪餅、醬料是小西紅柿番茄醬、芝士是馬蘇裏拉奶酪、蛤蜊是冷凍蛤蜊(由於不靠海)、蔬菜一樣是使用大蒜、洋蔥、蘑菇和紅辣椒。對象
原料的抽象工廠已經編寫完畢了,下面咱們的披薩店(PizzaStore)可使用原料的抽象工廠了。從新編輯一下PizzaStore,讓它能夠調用原料的抽象工廠,具體以下:接口
/** * 披薩店的工廠方法類。 * */ public abstract class PizzaStore { /** * 訂購一個披薩,須要告訴披薩店披薩的種類。 * */ public Pizza orderPizza(String type) { Pizza pizza; pizza = createPizza(type); // 加入原料。 pizza.prepare(); pizza.back(); pizza.cut(); pizza.box(); return pizza; } protected abstract Pizza createPizza(String type); } /** * 芝加哥披薩加盟店。 * */ public class ChicagoPizzaStore extends PizzaStore { /** * 建立芝加哥風味的披薩餅。 * */ protected Pizza createPizza(String type) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory(); if("cheese".equals(type)) { pizza = new CheesePizza(ingredientFactory); pizza.name = "芝加哥風味芝士披薩"; } else if ("veggie".equals(type)) { pizza = new VeggiePizza(ingredientFactory); pizza.name = "芝加哥風味素食披薩"; } else if ("clam".equals(type)) { pizza = new ClamPizza(ingredientFactory); pizza.name = "芝加哥風味蛤蜊披薩"; } return pizza; } } /** * 紐約披薩加盟店。 * */ public class NYPizzaStore extends PizzaStore { /** * 建立紐約風味的披薩餅。 * */ public Pizza createPizza(String type) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory(); if("cheese".equals(type)) { pizza = new CheesePizza(ingredientFactory); pizza.name = "紐約風味芝士披薩"; } else if ("veggie".equals(type)) { pizza = new VeggiePizza(ingredientFactory); pizza.name = "紐約風味素食披薩"; } else if ("clam".equals(type)) { pizza = new ClamPizza(ingredientFactory); pizza.name = "紐約風味蛤蜊披薩"; } return pizza; } }
咱們在工廠方法中,定義了原料抽象工廠ChicagoPizzaIngredientFactory和NYPizzaIngredientFactory,並在建立披薩時候,將原料抽象工廠經過構造函數傳遞給pizza對象,進而生成披薩所用的原料。
從工廠方法中能夠看出,在建立具體的pizza對象時,須要指定一個原料抽象工廠,用來建立一族原料,看看修改後的pizza對象是什麼樣子的:
public abstract class Pizza { String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Clam clam; /** * 收集披薩所需的原料,這些原料來自原料工廠。 * */ abstract void prepare(); void back() { System.out.println("--> 使用350度烘培25分鐘..."); } void cut() { System.out.println("--> 將披薩使用對角切片法切成8塊..."); } void box() { System.out.println("--> 使用對象村披薩店的盒子包裝...\n"); } @Override public String toString() { String pizzaInfo = "您選購的披薩是:" + name + ".\n"; if(dough != null) pizzaInfo += "使用的麪餅類型爲: " + dough.getName() + ".\n"; if(cheese != null) pizzaInfo += "選用的芝士是: " + cheese.getName() + ".\n"; if(veggies != null && veggies.length > 0) { pizzaInfo += "加入的蔬菜有: "; for(Veggies v : veggies) { pizzaInfo += v.getName() + "."; } pizzaInfo += "\n"; } if(sauce != null) pizzaInfo += "選用的醬料是: " + sauce.getName() + ".\n"; if(clam != null) pizzaInfo += "另外加入了: " + clam.getName() + ".\n"; return pizzaInfo; } }
Pizza的抽象類將prepare()方法也定義成了抽象的,由具體的Pizza類去實現:
/** * 芝士披薩,使用香濃的醬料和上好的芝士烘培而成。 */ public class CheesePizza extends Pizza { // 原料的抽象工廠接口。 PizzaIngredientFactory ingredientFactory; /** * 在構造披薩對象時,須要傳遞一個原料的抽象工廠。 */ public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } @Override void prepare() { System.out.println("--> 搭配製做芝士披薩的原料..."); super.dough = ingredientFactory.createDough(); super.sauce = ingredientFactory.createSauce(); super.cheese = ingredientFactory.createCheese(); } }
/** * 蛤蜊披薩,使用香濃的醬料和上好的芝士烘培,配上優質蛤蜊烘培而成。 */ public class ClamPizza extends Pizza { // 原料的抽象工廠接口。 PizzaIngredientFactory ingredientFactory; /** * 在構造披薩對象時,須要傳遞一個原料的抽象工廠。 */ public ClamPizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } @Override void prepare() { System.out.println("--> 搭配製做蛤蜊披薩的原料..."); super.dough = ingredientFactory.createDough(); super.sauce = ingredientFactory.createSauce(); super.cheese = ingredientFactory.createCheese(); super.clam = ingredientFactory.createClam(); } }
/** * 素食披薩,使用香濃的醬料和上好的芝士烘培,配上新鮮蔬菜烘培而成。 * */ public class VeggiePizza extends Pizza { // 原料的抽象工廠接口。 PizzaIngredientFactory ingredientFactory; /** * 在構造披薩對象時,須要傳遞一個原料的抽象工廠。 */ public VeggiePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } @Override void prepare() { System.out.println("--> 搭配製做素食披薩的原料..."); super.dough = ingredientFactory.createDough(); super.sauce = ingredientFactory.createSauce(); super.cheese = ingredientFactory.createCheese(); super.veggies = ingredientFactory.createVeggies(); } }
具體的Pizza對象中,聲明瞭原料的抽象工廠,在構造函數中初始化。重寫了prepare()方法,在該方法中調用原料抽象工廠的方法來建立原料。
public class Client { public static void main(String[] args) { // 紐約披薩店開張。 PizzaStore nyPizzaStore = new NYPizzaStore(); // 在紐約披薩店購買一張芝士披薩。 Pizza nyCheesePizza = nyPizzaStore.orderPizza("cheese"); System.out.println(nyCheesePizza); System.out.println("----------------------------------------\n"); // 購買一張紐約的蛤蜊披薩。 Pizza nyClamPizza = nyPizzaStore.orderPizza("clam"); System.out.println(nyClamPizza); System.out.println("----------------------------------------\n"); // 芝加哥披薩店開張。 PizzaStore chiPizzaStore = new ChicagoPizzaStore(); // 在芝加哥披薩店購買一張素食披薩。 Pizza chiVeggiePizza = chiPizzaStore.orderPizza("veggie"); System.out.println(chiVeggiePizza); } }
首先建立了紐約披薩店(NYPizzaStore),在紐約披薩店購買了一張芝士披薩和一張蛤蜊披薩,而後建立了一個芝加哥披薩店,購買了一張素食披薩,結果以下:
抽象工廠容許客戶用抽象的接口來建立一組相關的產品,而不須要知道(或關心)實際產出的產品具體是什麼。這樣易來,客戶就從具體的產品中被解耦。來看一個類圖:
抽象工廠定義了一個接口AbstractFactory,全部的具體工廠,也就是ConcreteCreator1和ConcreteCreator2必須實現此接口,這個接口包含一組方法用來生成產品。
這兩個具體工廠實現不一樣的產品家族。要建立一個產品,客戶只要使用其中一個工廠而徹底不須要實例化任何產品對象。
AbstractProductA和AbstractProductB都是產品家族的產品,每個具體工廠能生產一整組的產品。
以上就是抽象工廠的學習過程。