一、简单工厂
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。但由于经常被使用,所以给它一个“模式荣誉奖”。有些开发人员的确是把这个编程习惯误认为是“工厂模式”,不要因为简单工厂不是一个“真正的”模式,就忽略了它的用法。如下图显示的简单工厂使用类图(具体代码在文档最后列表中)。
★再提醒一次,在设计模式中,所谓的“实现以接口”并“不一定”表示“写一个类,并利用‘:’关键字来实现某个C#接口”。“实现一个接口”泛指“实现某个超类型(可以是类或接口)的某个方法”。
二、工厂方法模式
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
1.工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。如下类图,看看有哪些组成元素。
我们可以看到,将一个OrderPizza()方法和一个工厂方法联合起来,就可以成为一个框架。除此之外,工厂方法将生产知识封装进各个创建者,这样的做法,也可以被视为是一个框架。
如下图,看看这两个平行的类层级,并认清它们的关系:
2.工厂方法模式能够封装具体类型的实例化。看看下面的类图,抽象的Creator提供了一个创建对象的方法的接口,也称为“工厂方法”。在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品。
3.更多说明。
问:当只有一个ConcreteCreator的时候,工厂方法模式有什么优点?
答:尽管只有一个具体创建者,工厂方法模式依然很有用,因为它帮助我们将产品的“实现”从“使用”中解耦。如果增加产品或改变产品的实现,Creator并不会受到影响(因为Creator与任何ConcreteProduct之间都不是紧耦合)。
问:对于简单工厂和工厂方法之间的差异,我依然感到困惑。它们看起来很类似,差别在于,在工厂方法中,返回比萨的类是子类。能解释一下吗?
答:子类的确看起来像简单工厂。简单工厂把全部的事情,在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定要如何实现。比方说,在工厂方法中,OrderPizza()方法提供了一般的框架,以便创建比萨,OrderPizza()方法依赖工厂方法创建具体类,并制造出实际的比萨。可通过继承PizzaStore类,决定实际制造出的比萨是什么。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
根据上面的内容,我们可以推导出一个OO原则,即依赖倒置原则(Dependency Inversion Principle)
4.依赖倒置原则:要依赖抽象,不要依赖具体类。
首先,这个原则听起来很像是“针对接口编程,不针对实现编程”,不是吗?的确很相似,然而这里更强调“抽象”。这个原则说明了:不能让高层组件依赖底层组件,而且,不管高层或底层组件,“两者”都应该依赖于抽象。
★所谓“高层”组件,是由其它底层组件定义其行为的类。例如,PizzaStore是个高层组件,因为它的行为是由比萨定义的;PizzaStore创建所有不同的比萨对象,准备、烘烤、切片、装盒;而比萨本身属于底层组件。
想要遵循依赖倒置原则,工厂方法并非是唯一的技巧,但却是最有威力的技巧之一。
下面的指导方针,能帮你避免在OO设计中违反依赖倒置原则:
(1)变量不可以持有具体类的引用。(如果使用new,就会持有具体类的引用。你可以改用工厂来避开这样的做法)
(2)不要让类派生自具体类。(如果派生自具体类,你就会依赖具体类。请派生自一个抽象—接口、或抽象类)
(3)不要覆盖基类中已实现的方法。(如果覆盖基类已经实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享。)
三、抽象工厂模式
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
1.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。如下类图来了解其中的关系。
2.看看实际的关系类图,这是一张比较复杂的类图,我们可以从PizzaStore的观点来看看它。
四、总结
- 所有的工厂都是用来封装对象的创建。
- 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦。
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。
- 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。
- 所有工厂模式都通过减少,应用程序和具体类之间的依赖促进松耦合。
- 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。
五、代码列表
/// <summary> /// 比萨商店 /// </summary> public abstract class PizzaStore { public Pizza OrderPizza(string type) { Pizza pizza = CreatePizza(type); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } protected abstract Pizza CreatePizza(string type); } /// <summary> /// 纽约比萨 /// </summary> public class NYPizzaStore : PizzaStore { protected override Pizza CreatePizza(string type) { PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory(); Pizza pizza = null; switch (type) { case "cheese": pizza = new CheesePizza(ingredientFactory); pizza.Name = "New York Style Cheese Pizza"; break; case "veggie": pizza = new VeggiePizza(ingredientFactory); pizza.Name = "New York Style Veggie Pizza"; break; case "clam": pizza = new ClamPizza(ingredientFactory); pizza.Name = "New York Style Clam Pizza"; break; case "pepperoni": pizza = new PepperoniPizza(ingredientFactory); pizza.Name = "New York Style Pepperoni Pizza"; break; } return pizza; } } /// <summary> /// 纽约披萨原料工厂 /// </summary> public class NYPizzaIngredientFactory : 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(); } } /// <summary> /// 芝加哥披萨原料工厂 /// </summary> public class ChicagoPizzaIngredientFactory : 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 BlackOlives(), new Spinach(), new EggPlant() }; return veggies; } public Pepperoni CreatePepperoni() { return new SlicedPepperoni(); } public Clams CreateClam() { return new FrozenClams(); } } /// <summary> /// 芝加哥比萨商店 /// </summary> public class ChicagoPizzaStore : PizzaStore { protected override Pizza CreatePizza(string type) { PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory(); Pizza pizza = null; switch (type) { case "cheese": pizza = new CheesePizza(ingredientFactory); pizza.Name = "Chicago Style Cheese Pizza"; break; case "veggie": pizza = new VeggiePizza(ingredientFactory); pizza.Name = "Chicago Style Veggie Pizza"; break; case "clam": pizza = new ClamPizza(ingredientFactory); pizza.Name = "Chicago Style Clam Pizza"; break; case "pepperoni": pizza = new PepperoniPizza(ingredientFactory); pizza.Name = "Chicago Style Pepperoni Pizza"; break; } return pizza; } } /// <summary> /// 披萨 /// </summary> public abstract class Pizza { public string Name { get; set; } /// <summary> /// 材料:生面团 /// </summary> public Dough MyDough { get; set; } /// <summary> /// 材料:酱油、调味汁 /// </summary> public Sauce MySauce { get; set; } /// <summary> /// 材料:蔬菜 /// </summary> public Veggies[] MyVeggies { get; set; } /// <summary> /// 材料:奶酪 /// </summary> public Cheese MyCheese { get; set; } /// <summary> /// 材料:意大利辣香肠 /// </summary> public Pepperoni MyPepperoni { get; set; } /// <summary> /// 材料:蛤蚌 /// </summary> public Clams MyClams { get; set; } /// <summary> /// 预备 /// </summary> public abstract void Prepare(); /// <summary> /// 烘烤 /// </summary> public void Bake() { Console.WriteLine("Bake for 25 minutes as 350"); } /// <summary> /// 切片 /// </summary> public void Cut() { Console.WriteLine("Cutting the pizza into diagonal slices"); } /// <summary> /// 装箱 /// </summary> public void Box() { Console.WriteLine("Place pizza in official PizzaStore box"); } public override string ToString() { return "more pizza content"; } } /// <summary> /// 奶酪披萨 /// </summary> public class CheesePizza : Pizza { private PizzaIngredientFactory ingredientFactory; public CheesePizza(PizzaIngredientFactory _ingredientFactory) { ingredientFactory = _ingredientFactory; } public override void Prepare() { Console.WriteLine("Preparing {0}", Name); Console.WriteLine(" ingredient:Dough,Sauce,Cheese"); MyDough = ingredientFactory.CreateDough(); MySauce = ingredientFactory.CreateSauce(); MyCheese = ingredientFactory.CreateCheese(); } } /// <summary> /// 蛤蚌比萨 /// </summary> public class ClamPizza : Pizza { private PizzaIngredientFactory ingredientFactory; public ClamPizza(PizzaIngredientFactory _ingredientFactory) { ingredientFactory = _ingredientFactory; } public override void Prepare() { Console.WriteLine("Preparing {0}", Name); Console.WriteLine(" ingredient:Dough,Sauce,Cheese,Clam"); MyDough = ingredientFactory.CreateDough(); MySauce = ingredientFactory.CreateSauce(); MyCheese = ingredientFactory.CreateCheese(); MyClams = ingredientFactory.CreateClam(); } } /// <summary> /// 辣香肠比萨 /// </summary> public class PepperoniPizza : Pizza { private PizzaIngredientFactory ingredientFactory; public PepperoniPizza(PizzaIngredientFactory _ingredientFactory) { ingredientFactory = _ingredientFactory; } public override void Prepare() { Console.WriteLine("Preparing {0}", Name); Console.WriteLine(" ingredient:Dough,Sauce,Pepperoni"); MyDough = ingredientFactory.CreateDough(); MySauce = ingredientFactory.CreateSauce(); MyPepperoni = ingredientFactory.CreatePepperoni(); } } /// <summary> /// 蔬菜比萨 /// </summary> public class VeggiePizza : Pizza { private PizzaIngredientFactory ingredientFactory; public VeggiePizza(PizzaIngredientFactory _ingredientFactory) { ingredientFactory = _ingredientFactory; } public override void Prepare() { Console.WriteLine("Preparing {0}", Name); Console.WriteLine(" ingredient:Dough,Sauce,Veggies"); MyDough = ingredientFactory.CreateDough(); MySauce = ingredientFactory.CreateSauce(); MyVeggies = ingredientFactory.CreateVeggies(); } } /// <summary> /// 简单比萨工厂 /// </summary> public class SimplePizzaFacotry { public Pizza CreatePizza(string type) { Pizza pizza = null; switch (type) { case "cheese": pizza = new CheesePizza(null); break; case "pepperoni": pizza = new PepperoniPizza(null); break; case "veggie": pizza = new VeggiePizza(null); break; case "clam": pizza = new ClamPizza(null); break; } return pizza; } } /// <summary> /// 奶酪 /// </summary> public abstract class Cheese { } /// <summary> /// 巴马干酪 /// </summary> public class ReggianoCheese : Cheese { } /// <summary> /// 马苏里拉奶酪 /// </summary> public class MozzarellaCheese : Cheese { } /// <summary> /// 山羊乳干酪 /// </summary> public class GoatCheese : Cheese { } /// <summary> /// 蛤蚌 /// </summary> public abstract class Clams { } /// <summary> /// 新鲜蛤蚌 /// </summary> public class FreshClams : Clams { } /// <summary> /// 冰冻蛤蚌 /// </summary> public class FrozenClams : Clams { } /// <summary> /// 鱿鱼蛤蚌 /// </summary> public class CalamariClams : Clams { } /// <summary> /// 生面团 /// </summary> public abstract class Dough { } /// <summary> /// 稀薄面团 /// </summary> public class ThinCrustDough : Dough { } /// <summary> /// 加厚面团 /// </summary> public class ThickCrustDough : Dough { } /// <summary> /// 很薄面团 /// </summary> public class VeryThinCrustDough : Dough { } /// <summary> /// 意大利辣香肠 /// </summary> public abstract class Pepperoni { } /// <summary> /// 切片意大利辣香肠 /// </summary> public class SlicedPepperoni : Pepperoni { } /// <summary> /// 酱油、调味汁 /// </summary> public abstract class Sauce { } /// <summary> /// 海员式沙司 /// </summary> public class MarinaraSauce : Sauce { } /// <summary> /// 梨形番茄 /// </summary> public class PlumTomatoSauce : Sauce { } /// <summary> /// 蒜末沙拉 /// </summary> public class BruschettaSauce : Sauce { } /// <summary> /// 蔬菜 /// </summary> public abstract class Veggies { } /// <summary> /// 大蒜 /// </summary> public class Garlic : Veggies { } /// <summary> /// 洋葱 /// </summary> public class Onion : Veggies { } /// <summary> /// 蘑菇 /// </summary> public class Mushroom : Veggies { } /// <summary> /// 红辣椒 /// </summary> public class RedPepper : Veggies { } /// <summary> /// 菠菜 /// </summary> public class Spinach : Veggies { } /// <summary> /// 乌榄 /// </summary> public class BlackOlives : Veggies { } /// <summary> /// 茄子 /// </summary> public class EggPlant : Veggies { }
-----------------------------以上内容根据《Head First 设计模式》进行整理