抽象工厂模式的定义是:
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
实现 上一篇工厂方法模式(Factory Method Pattern) 中,我们已经能生产不同区域的不同披萨了,但是每家店使用的原料都是不一致的,做为一个好的连锁店,我们需要确保原料的高质量。这里需要注意的是,即使是同一种披萨,在不同的区域使用的原料也是会有区别的,会根据当地人的口味进行调整,那么为了保证以上两点,我们需要建立原料的工厂。
首先,即使原料略有不同,但是原料的种类就是那么几种:面团(Dough)、酱(Sauce)、起司(Cheese)、蔬菜(Veggies)、意大利辣香肠(Pepperoni)和蛤(Clam)。
大多数的披萨,都是由上面这些原料组成的,所以我们的原料工厂要保证能生产这些原料:
1 2 3 4 5 6 7 8 9 10 11 12 public interface PizzaIngredientFactory { public IDough createDough () ; public ISauce createSauce () ; public ICheese createCheese () ; public IVeggies[] createVeggies () ; public IPepperoni createPepperoni () ; public IClams createClam () ; }
每种原料下面又分成好多种不同地区的原料,以面团为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 namespace DesignPattern.AbstractFactoryPattern { public interface IDough { public string ToString () ; } public class ThickCrustDough : IDough { public override string ToString () { return "厚皮面团" ; } } public class ThinCrustDough : IDough { public override string ToString () { return "薄皮面团" ; } } }
其他种类的原料也是类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 namespace DesignPattern.AbstractFactoryPattern { public interface ISauce { public string ToString () ; } public class MarinaraSauce : ISauce { public string ToString () { return "意大利西红柿酱" ; } } public class PlumTomatoSauce : ISauce { public string ToString () { return "梅子西红柿酱" ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 namespace DesignPattern.AbstractFactoryPattern { public interface ICheese { public string ToString () ; } public class MozzarellaCheese : ICheese { public string ToString () { return "芝士丝" ; } } public class ParmesanCheese : ICheese { public string ToString () { return "帕尔马干酪" ; } } public class ReggianoCheese : ICheese { public string ToString () { return "雷吉亚诺奶酪" ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 namespace DesignPattern.AbstractFactoryPattern { public interface IVeggies { public string ToString () ; } public class Eggplant : IVeggies { public override string ToString () { return "茄子" ; } } public class Garlic : IVeggies { public override string ToString () { return "大蒜" ; } } public class Spinach : IVeggies { public override string ToString () { return "菠菜" ; } } public class Onion : IVeggies { public override string ToString () { return "洋葱" ; } } public class Mushroom : IVeggies { public override string ToString () { return "蘑菇" ; } } public class RedPepper : IVeggies { public override string ToString () { return "辣椒" ; } } public class BlackOlives : IVeggies { public override string ToString () { return "黑橄榄" ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 namespace DesignPattern.AbstractFactoryPattern { public interface IPepperoni { public string ToString () ; } public class SlicedPepperoni : IPepperoni { public override String ToString () { return "切意大利辣香肠" ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 namespace DesignPattern.AbstractFactoryPattern { public interface IClams { public string ToString () ; } public class FreshClams : IClams { public override String ToString () { return "长岛之声的新鲜蛤" ; } } public class FrozenClams : IClams { public override String ToString () { return "切萨皮克湾的冷冻蛤" ; } } }
接下来,我们就可以根据原料工厂来创建不同地区的原料工厂了,以纽约原料工厂为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class NYPizzaIngredientFactory : PizzaIngredientFactory { public IDough createDough () { return new ThinCrustDough(); } public ISauce createSauce () { return new MarinaraSauce(); } public ICheese createCheese () { return new ReggianoCheese(); } public IVeggies[] createVeggies () { IVeggies[] veggies = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; return veggies; } public IPepperoni createPepperoni () { return new SlicedPepperoni(); } public IClams createClam () { return new FreshClams(); } }
同样的,芝加哥原料工厂如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class ChicagoPizzaIngredientFactory : PizzaIngredientFactory { public IDough createDough () { return new ThickCrustDough(); } public ISauce createSauce () { return new PlumTomatoSauce(); } public ICheese createCheese () { return new MozzarellaCheese(); } public IVeggies[] createVeggies () { IVeggies[] veggies = { new BlackOlives(), new Spinach(), new Eggplant() }; return veggies; } public IPepperoni createPepperoni () { return new SlicedPepperoni(); } public IClams createClam () { return new FrozenClams(); } }
现在,所有的原料已经准备完成,我们需要修改一下披萨,使其只能使用我们原料工厂提供的原料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public abstract class Pizza { public String name; public IDough dough; public ISauce sauce; public IVeggies[] veggies; public ICheese cheese; public IPepperoni pepperoni; public IClams clam; public abstract void prepare () ; public void bake () { Console.WriteLine("350摄氏度烘焙25分钟。" ); } public void cut () { Console.WriteLine("将披萨切成对角。" ); } public void box () { Console.WriteLine("将披萨放入盒中" ); } public void setName (String name ) { this .name = name; } public String getName () { return name; } public override String ToString () { StringBuilder result = new StringBuilder(); 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(); } }
在抽象类 Pizza
中,prepare
方法也被定义为抽象方法,因为这里我们需要根据不同的披萨生成不同的原料。
接下来,我们就可以制作披萨了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CheesePizza : Pizza { PizzaIngredientFactory ingredientFactory; public CheesePizza (PizzaIngredientFactory ingredientFactory ) { this .ingredientFactory = ingredientFactory; } public override void prepare () { Console.WriteLine("准备:" + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); } }
在重写的 prepare
方法中,当我们需要什么原料我们只要向原料工厂要就行了。具体是什么原料,由原料工厂来决定,纽约的原料工厂就给纽约风格的原料,芝加哥的原料工厂就给芝加哥风格的原料。
同样的,蛤蜊披萨也是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ClamPizza : Pizza { PizzaIngredientFactory ingredientFactory; public ClamPizza (PizzaIngredientFactory ingredientFactory ) { this .ingredientFactory = ingredientFactory; } public override void prepare () { Console.WriteLine("准备:" + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); clam = ingredientFactory.createClam(); } }
相对于 CheesePizza
,ClamPizza
多了蛤蜊作为原谅,至于蛤蜊的种类,就由所在地的工厂来决定。如果是靠海的纽约,那就可以拿到新鲜的蛤蜊,如果是内陆的芝加哥,那么就只能使用冷冻的蛤蜊了。
另外两种披萨:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class VeggiePizza : Pizza { PizzaIngredientFactory ingredientFactory; public VeggiePizza (PizzaIngredientFactory ingredientFactory ) { this .ingredientFactory = ingredientFactory; } public override void prepare () { Console.WriteLine("准备:" + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); veggies = ingredientFactory.createVeggies(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class PepperoniPizza : Pizza { PizzaIngredientFactory ingredientFactory; public PepperoniPizza (PizzaIngredientFactory ingredientFactory ) { this .ingredientFactory = ingredientFactory; } public override void prepare () { Console.WriteLine("准备:" + name); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); cheese = ingredientFactory.createCheese(); veggies = ingredientFactory.createVeggies(); pepperoni = ingredientFactory.createPepperoni(); } }
再回到披萨店:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class PizzaStore { protected abstract Pizza createPizza (String item ) ; public Pizza orderPizza (String type ) { Pizza pizza = createPizza(type); Console.WriteLine("制作一个" + pizza.getName()); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
创建纽约披萨加盟店和芝加哥披萨加盟店:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class NYPizzaStore : PizzaStore { protected override Pizza createPizza (string item ) { Pizza pizza = null ; PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory(); if (item.Equals("cheese" )) { pizza = new CheesePizza(ingredientFactory); pizza.setName("纽约风格芝士披萨" ); } else if (item.Equals("veggie" )) { pizza = new VeggiePizza(ingredientFactory); pizza.setName("纽约风格素食披萨" ); } else if (item.Equals("clam" )) { pizza = new ClamPizza(ingredientFactory); pizza.setName("纽约风格蛤蜊披萨" ); } else if (item.Equals("pepperoni" )) { pizza = new PepperoniPizza(ingredientFactory); pizza.setName("纽约风格意大利辣香肠披萨" ); } return pizza; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class ChicagoPizzaStore : PizzaStore { protected override Pizza createPizza (string item ) { Pizza pizza = null ; PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory(); if (item.Equals("cheese" )) { pizza = new CheesePizza(ingredientFactory); pizza.setName("芝加哥风格芝士披萨" ); } else if (item.Equals("veggie" )) { pizza = new VeggiePizza(ingredientFactory); pizza.setName("芝加哥风格素食披萨" ); } else if (item.Equals("clam" )) { pizza = new ClamPizza(ingredientFactory); pizza.setName("芝加哥风格蛤蜊披萨" ); } else if (item.Equals("pepperoni" )) { pizza = new PepperoniPizza(ingredientFactory); pizza.setName("芝加哥风格意大利辣香肠披萨" ); } return pizza; } }
这两家披萨店就是抽象工厂的客户,如果想生产纽约风格的披萨,只需要使用纽约披萨原料工厂提供的原料。
注意的点
抽象工厂定义了一个接口,所有的具体工厂都必须实现此接口。
在客户的代码中,只需要涉及抽象工厂,当运行时将自动使用实际的具体工厂。
当需要创建产品家族和想让制造的相关产品集合起来时,可以使用抽象工厂,而当目前还不知道将来需要实例化哪些具体类时,就可以使用工厂方法。
代码 AbstractFactoryPattern
最后 最后让我们点个披萨吃吧:
1 2 PizzaStore nyStore = new NYPizzaStore(); Pizza pizza = nyStore.orderPizza("cheese" );