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都是產品家族的產品,每個具體工廠能生產一整組的產品。

    以上就是抽象工廠的學習過程。

相關文章
相關標籤/搜索