设计模式 -- 工厂方法
理解了简单工厂就不难理解工厂方法,工厂方法没有了“工厂”这个类,它是用抽象方法实现的,这就涉及到了“多态”。子类实现父类的抽象方法,也就是把“生产对象”这个职责从工厂中拿出来让具体类来实现。
举个例子来说吧,有一个Pizza店,它有很多子类,有纽约风味的Pizza店,还有芝加哥风味的Piiza店,不同的Pizza店有cheesePizza,ClamPizza,VeggiesPizza,PepperoniPizza四种不同口味的Piiza.我们知道不同的风味的店在你不同的地区,而且一个风味的Pizza店只能点这中风味的Piiza。如果要用简单工厂来实现这个例子,那么在简单工厂的createPizza(参数)的参数中我们至少要传进来“风味”和“口味”两个不同的参数,这样就会使得Pizza的“口味”和“风味”严重的依赖,而且我们已经说了,一个风味的Pizza店只能点这中风味的Piiza,所以看到了,用简单工厂来实现这个例子是不理想的。那么我们看看“工厂方法”。
1、什么是“工厂方法”?
工厂方法是一个抽象类的抽象方法。它定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
2、“工厂方法”如何实现?
还以上面的例子说明,在Pizza店里点Pizza的时候会说明是什么口味的,这个时候,如果你在纽约的Pizza店里,那么给你呈上来的就是纽约风味中这个口味的,如果你是在芝加哥呢,那么你将享用芝加哥风味中这个口味的。所以我们看到了,我们得有两个风味的Pizza店(纽约风味店和芝加哥风味店),然后每个店实现继承自Piiza店的createPizza(参数)的方法,这样每个店就能按照自己的风味来制作不同的口味的Pizza了。那么你在吃Pizza前就得选择好要哪个风味的,根据你的选择我们选择不同的风味店。看看这个类图吧:
3、示例代码:
public abstract class PizzaStore { /* * 从工厂类中把建造对象的方法拿出来,让具体的类来实现, * 这就是工厂方法,工厂方法用来处理对象的创建,并将这样的 * 行为封装在子类中,这样,客户程序中,关于超类代码和子类 * 对象创建代码解耦了 */ public abstract Pizza createPizza(string type); public Pizza orderPizza(string type) { Pizza pizza; pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
//芝加哥风味Pizza店 public class ChicagoStylePizzaStore : PizzaStore { public override Pizza createPizza(string type) { Pizza pizza = null; if (type == "cheese")//让子类决定该创建什么对象 { pizza = new ChicagoStyleCheesePizza(); } else if (type == "clam") { pizza = new ChicagoStyleClamPizza(); } else if (type == "pepperoni") { pizza = new ChicagoPepperoniPizza(); } else if (type == "veggie") { pizza = new ChicagoVeggiePizza(); } return pizza; } }
//纽约风味Pizza店 public class NYStylePizzaStore : PizzaStore { public override Pizza createPizza(string type) { Pizza pizza = null; if (type == "cheese") { pizza = new NYStyleCheesePizza(); } else if (type == "clam") { pizza = new NYStyleClamPizza(); } else if (type == "pepperoni") { pizza = new NYStylePepperoniPizza(); } else if (type == "veggie") { pizza = new NYStyleVeggiePizza(); } return pizza; } }
//pizza类 public abstract class Pizza { public string name; public string Name { get { return name; } set { name = value; } } public string dough;//面团 public string sauce;//调料 public ArrayList toppings = new ArrayList(); public void prepare() { Console.WriteLine("preparing: " + name); Console.WriteLine("Tossing dough……"); Console.WriteLine("Adding sauce……"); Console.WriteLine("Adding Toppings……"); for (int i = 0; i < toppings.Count;i++ ) { Console.WriteLine(" " + toppings[i]); } } public void bake() { Console.WriteLine("Bake for 25 minutes at 350"); } public void cut() { Console.WriteLine("cutting the pizza into diagonal slices"); } public void box() { Console.WriteLine("place pizza into box"); } }
//芝加哥风味的奶酪Pizza,这个类实现了自己的切Pizza方法。 public class ChicagoStyleCheesePizza : Pizza { public ChicagoStyleCheesePizza() { Name = "Chicago style deep dish Cheese pizza"; dough = "extra thick crust dough"; sauce = "plum potato sauce"; toppings.Add("shredded mozzarella Cheese"); } public void cut() { Console.WriteLine("Cutting the pizza into square slices"); } }
static void Main(string[] args) { PizzaStore nyStore = new NYStylePizzaStore(); PizzaStore chicagoStore = new ChicagoStylePizzaStore(); Pizza pizza = nyStore.orderPizza("cheese"); Console.WriteLine("Ethan ordered a " + pizza.Name+"\n"); pizza = chicagoStore.orderPizza("cheese"); Console.WriteLine("Jole oedered a " + pizza.Name + "\n"); Console.ReadKey(); }
其他的几类Pizza的子类就不一一列出来了。
4、设计原则
4.1、解耦 工厂方法用来处理对象的创建,并将这样的行为封装在子类中,这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。
4.2、依赖倒置原则:要依赖抽象,而不依赖具体。这个原则是说不能让高层组件依赖底层组件,并且不管是高层组件还是底层组件,两者都应该依赖于抽象。这是什么意思呢?在我们这个例子中,pizzaStore就是个高层组件,而那些具体的pizza就是h底层组件。如果按照我们最初的按照简单工厂的方法实现的话,就或出现高层组件依赖于底层组件的现象。现在,我们用工厂方法实现之后,这两个组件都开始依赖Pizza这个抽象。那么“倒置”到底发生在什么地方?看看,我们的类图,就能发现,底层组件现在依赖于高层抽象,同样的,高层组件也依赖于相同的抽象。