定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
从PizzaStore的角度,来理解上面的这个类图:
抽象工厂的任务是,定义一个创建一组产品的接口。这个接口内的每个方法都负责创建一组产品。同时,我们利用实现抽象工厂的子类来提供这些具体的做法。
我们来看一个例子
/**
* @author ZerlindaLi create at 2019/8/15 15:15
* @version 1.0.0
* @description PizzaIngredientFactory
* 开始先为工厂定义一个接口,这个接口负责创建所有的原料
*/
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
/**
* @author ZerlindaLi create at 2019/8/15 15:30
* @version 1.0.0
* @description NYPizzaIngredientFactory
* 这是纽约原料工厂的实现。这工厂专精于大蒜番茄酱料、Reggiano干酪、新鲜哈利···
* 具体原料工厂必须实现PizzaIngredientFactory这个接口,纽约原料工厂也不例外
*/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Veggies[] createVeggies() {
// 对于蔬菜,以一个蔬菜数组为返回值。在这里我们是直接把蔬菜写死。
// 其实我们可以把它改写得更好一点,但是这对于学习工厂模式并没有帮助,所以还是保持这个简单的做法就好了。
Veggies veggies [] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};
return veggies;
}
@Override
public Pepperoni createPepperoni() {
// 这是切片的意式腊肠,纽约和芝加哥都会用到它。在下一页,在你自己实现芝加哥工厂时,别忘了使用它。
return new SlicedPepperoni();
}
@Override
public Clams createClam() {
// 纽约靠海,所以有新鲜的蛤蜊。芝加哥就必须使用冷冻的蛤蜊
return new FreshClams();
}
}
/**
* @author ZerlindaLi create at 2019/8/12 16:49
* @version 1.0.0
* @description 抽象PizzaStore 创建者类
* 这是抽象创建者类,它定义了一个抽象的工厂方法,让子类实现此方法制造产品
* 创建者通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造。创建者不需要真的知道在制造哪种具体产品。
*/
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza;
// createPizza()方法从工厂对象中移回PizzaStore
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// 现在把工厂对象移到这个方法中,现在是抽象的
abstract Pizza createPizza(String type);
}
/**
* @author ZerlindaLi create at 2019/8/13 16:04
* @version 1.0.0
* @description NYPizzaStore 能够产生产品的类成为具体创建者
*/
public class NYPizzaStore extends PizzaStore{
/**
* 此方法正是工厂方法,用来制造产品。
* 因为每个加盟店都有自己的PizzaStore子类,所以可以用实现createPizza()创建自己风味的披萨
* @param item
* @return
*/
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;
}
}
/**
* @author ZerlindaLi create at 2019/8/13 15:00
* @version 1.0.0
* @description Pizza 工厂生产产品。对PizzaStore来说,产品就是Pizza.
*/
public abstract class Pizza {
// 每个披萨都持有一组在准备时会用到的原料
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
// 现在把prepare()方法声明成抽象。在这个方法中,我们需要收集披萨所需的原料,而这些原料当然是来自原料工厂了。
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");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
// 这里是打印披萨的代码
return name;
}
}
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
// 蛤蜊披萨也需要原料工厂
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
System.out.println("Preparing " + name);
// 要做出蛤蜊披萨,prepare()方法就必须从本地工厂中取得正确的原料。
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
// 如果是纽约工厂,就会使用新鲜的蛤蜊,如果是芝加哥工厂,就是冷冻的蛤蜊
clam = ingredientFactory.createClam();
}
}
public class VeggiePizza extends Pizza {
PizzaIngredientFactory pizzaIngredientFactory;
public VeggiePizza(PizzaIngredientFactory pizzaIngredientFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
void prepare() {
System.out.println("Preparing " + name);
// 神奇的事情发生在这里!
// prepare()方法一步一步地创建芝士披萨,每当需要原料时,就更工厂要。
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}
}
下面请看原材料
public interface Dough {
}
public class ThinCrustDough implements Dough {
}
public interface Sauce {
}
public class MarinaraSauce implements Sauce {
}