HeadFirst设计模式(四) - 工厂模式之3 - 抽象工厂

保持一致的原料

    前面的简单工厂和工厂方法,咱们用了披萨店生产披萨作了例子,接下来使用生产披萨原料(面团、酱料、蔬菜、肉等等)来描述一下抽象工厂。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对象时,须要指定一个原料抽象工厂,用来建立一族原料,看看修改后的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都是产品家族的产品,每个具体工厂能生产一整组的产品。

    以上就是抽象工厂的学习过程。

相关文章
相关标签/搜索