意图:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
结构:
实例:还是以Pizza店为例,现在pizza需要进行需要不同的原料,例如添加cheese,sauce等原料,重新扩展的pizza为:
package headfirst.factory.pizzaaf; public abstract class Pizza { String name; Dough dough; Sauce sauce; Veggies veggies[]; Cheese cheese; Pepperoni pepperoni; Clams clam; abstract void prepare(); void bake() { System.out.println("Bake for 25 minutes at 350"); } 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() { return name; } public String toString() { StringBuffer result = new StringBuffer(); result.append("---- " + name + " ----\n"); if (dough != null) { result.append(dough); result.append("\n"); } if (sauce != null) { result.append(sauce); result.append("\n"); } if (cheese != null) { result.append(cheese); result.append("\n"); } if (veggies != null) { for (int i = 0; i < veggies.length; i++) { result.append(veggies[i]); if (i < veggies.length-1) { result.append(", "); } } result.append("\n"); } if (clam != null) { result.append(clam); result.append("\n"); } if (pepperoni != null) { result.append(pepperoni); result.append("\n"); } return result.toString(); } }
然后我们定义一个抽象工厂PizzaIngredientFactory:
package headfirst.factory.pizzaaf; public interface PizzaIngredientFactory { public Dough createDough(); public Sauce createSauce(); public Cheese createCheese(); public Veggies[] createVeggies(); public Pepperoni createPepperoni(); public Clams createClam(); }
继续我们假设有一个纽约的原料工厂,精于大蒜番茄酱料,Reggiano干酪,新鲜蛤蜊........
package headfirst.factory.pizzaaf; 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 Pepperoni createPepperoni() { return new SlicedPepperoni(); } public Clams createClam() { return new FreshClams(); } }
然后我们现在创建一个奶酪pizza
package headfirst.factory.pizzaaf; public class CheesePizza extends Pizza { PizzaIngredientFactory ingredientFactory; public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; } void prepare() { System.out.println("Preparing " + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); } }
最后我们来看这个纽约的pizza店,怎么用纽约的原料工厂创建出具有纽约风味的cheese的pizza:
package headfirst.factory.pizzaaf; public class NYPizzaStore extends PizzaStore { protected Pizza createPizza(String item) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory(); if (item.equals("cheese")) { pizza = new CheesePizza(ingredientFactory); pizza.setName("New York Style Cheese Pizza"); } else if (item.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory); pizza.setName("New York Style Veggie Pizza"); } else if (item.equals("clam")) { pizza = new ClamPizza(ingredientFactory); pizza.setName("New York Style Clam Pizza"); } else if (item.equals("pepperoni")) { pizza = new PepperoniPizza(ingredientFactory); pizza.setName("New York Style Pepperoni Pizza"); } return pizza; } }
最后我们来看最后的类图:
1.工厂方法潜伏在抽象工厂模式之下,例如上面我们说的createDough(),createSource()方法,这些其实都在被继承的时候,然后来实现实例化的。
2.抽象工厂和工厂方法都是创建对象,工厂方法是“继承”(把对象的创建委托给子类,子类实现工厂方法来创建对象),抽象工厂通过对象的组合(对象的创建被实现在工厂接口暴露出来的方法中),抽象工厂产品家族和想让制造的相关的产品集合起来,而工厂方法可以让实例通过子类进行决定。
3.提醒我们随时要针对接口编程,而不是对实现编程。
缺点:
如果要增加相应的产品,相应的继承子类也要进行修改。繁琐。