简单工厂模式/工厂方法模式--Head First设计模式【笔记】
在了解工厂方法模式前,我们先来了解一下简单工厂模式。
一、简单工厂模式
我家开了一个Pizza店,代码如下:
public class PizzaStore { public Pizza orderPizza(string type) { Pizza pizza; //根据Pizza类型,我们实例化正确的具体类。 //这里的任何Pizza都必须实现Pizza接口 if (type.Equals("cheese")) { pizza = new CheesePizza(); }else if (type .Equals ("greek")) { pizza = new GreekPizza(); }else if (type .Equals ("pepperoni")) { pizza = new PepperoniPizza(); } //pizza 的一些制作流程 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
看上面红色部分的代码,它是产生不同风味的Pizza的代码。
这样就存在一个问题:如果市场需求变化(出现新的风味的Pizza需求),那我们就要对这段代码一改再改。
违反了我们的设计原则:类应该对扩展开发,对修改关闭。
那怎么办?
想想我们的设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
我们把红色部分的代码剪切出来放到另一个对象SimplePizzaFactory中,由SimplePizzaFactory专门负责生产不同风味的Pizza。
//重做PizzaStore类
public class PizzaStore { //为PizzaStore加上一个对SimplePizzaFactory的引用 SimplePizzaFactory factory; //PizzaStore的构造器需要一个工厂作为参数 public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; } public Pizza orderPizza(string type) { Pizza pizza; //orderPizza()方法通过简单传入订单类型来使用工厂创建Pizza pizza = factory.createPizza(type ); //pizza 的一些制作流程 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
//简单工厂
public class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null;
//红色代码剪切到这里 if (type.Equals("cheese")) { pizza = new CheesePizza(); } else if (type.Equals("greek")) { pizza = new GreekPizza(); } else if (type.Equals("pepperoni")) { pizza = new PepperoniPizza(); } return pizza; } }
到这里你可能要问了:这么做有什么好处啊?似乎只是把问题搬到另一个对象罢了,问题依然存在。
答:别忘了,SimplePizzaFactory可以有许多的客户,虽然目前只看到orderPizza()方法是它的客户,
然而,可能还有PizzaShopMenu(比萨店菜单)类,会利用这个工厂来取得比萨的价钱和描述。
所以,把创建比萨的代码包装进一个类,当以后实现改变时,只需要修改这个类即可。
-----------------------------------------------------------
经过团队不断的努力,我家的Pizza店的产品深受消费者的喜欢,其他人的Pizza店想加盟我家的Pizza店。
加盟可以,但是我家的Pizza店有要求:要使用我家的代码,保证Pizza的制作流程能一致。
加盟店主也提出了一点自己的想法:希望工厂能够制作出加盟店本地(加盟店地址和我家的Pizza店不在同一区域)风味的Pizza。
需求解析:
制作流程一致,那我们很容易想到继承。加盟店继承我家的Pizza店的代码,那就能复用制作流程,保证制作流程一致性。
加盟店想要本地风味的Pizza,即加盟店想自己决定Pizza的风味,那么我们把PizzaStore类中的Pizza的创建代码pizza = factory.createPizza(type );改为一个抽象方法,让继承加盟店自己来实现。
额!!这不就是工厂方法模式吗?
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
让我们看下代码吧:
//重写PizzaStore public abstract class PizzaStore { public Pizza orderPizza(string type) { Pizza pizza; //创建对象pizza的接口 pizza = createPizza(type ); //pizza 的一些制作流程 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } // 让子类决定实例化哪个类(即哪个风味的Pizza) protected abstract Pizza createPizza(String type); }
//本地加盟店 public class BenDiPizzaStore:PizzaStore { // 什么风味的Pizza是由加盟店自己决定的 protected override Pizza createPizza(string type) { Pizza pizza = null; if (type.Equals("ChicagoPizza")) { pizza = new ChicagoPizza(); } else if (type.Equals("NYSPizza")) { pizza = new NYSPizza(); } return pizza; } }
//加盟店中NYSPizza风味的Pizza class NYSPizza:Pizza { public NYSPizza() { name = "BenDi Style Sauce and Cheese Pizza"; dough = "Thin Crust Dough"; sauce = "Marinara Sauce"; toppings.Add("Grated Reggiano Cheese"); } }
//加盟店中 ChicagoPizza风味的Pizza class ChicagoPizza:Pizza { public ChicagoPizza() { name = "BenDi Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.Add("Shredded Mozzarella Cheese"); } //加盟店中ChicagoPizza风味的Pizza特殊切法,在流程一致的基础上,有加盟店本地化的元素。 void cut() { Console.WriteLine("Cutting the pizza into square slices"); } }
篇幅所限,我就只写了一个加盟店和两种风味的Pizza,有兴趣的朋友可以自己多些几个加盟店和不同风味的Pizza。
//重要角色 Pizza public abstract class Pizza { protected string name; protected string dough; protected string sauce; protected 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 in official PizzaStore box"); } public string getName() { return name; } }
调试下:Pizza开卖了!!!
static void Main(string[] args) { PizzaStore bdStore = new BenDiPizzaStore(); bdStore.orderPizza("ChicagoPizza"); Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); bdStore.orderPizza("NYSPizza"); Console.ReadKey(); }
显示:
待续:
抽象工厂模式:定义一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
目前我的理解:我要创建一个对象,而这个对象有些相关或者说依赖的部分是变化的,是时常改动的。这时候我通过为这一系列定义一个接口,让变化实现这个接口。而对象的构造函数以这个接口为传入的参数,那么我们就可以调用这个接口的一系列变化,达到完整创建这个对象的目的。而这个一系列变化就不需要明确指定具体类,而是由创建实例对象时以实现这个接口的类做参数传进来的。(抽象工厂模式,我目前还无法用自己的话完整的表达出来,希望不要误导大家。先记这边,等理解深刻了用通俗易懂的方式展现给大家)。