前面的简单工厂和工厂方法,咱们用了披萨店生产披萨作了例子,接下来使用生产披萨原料(面团、酱料、蔬菜、肉等等)来描述一下抽象工厂。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都是产品家族的产品,每个具体工厂能生产一整组的产品。
以上就是抽象工厂的学习过程。