《Head.First设计模式》的学习笔记(5)--工厂方法模式

意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

结构

image

实例:下面我们以Pizza店的例子来谈谈“工厂方法模式”的来龙去脉,我们学习的思路是“原始设计-->简单工厂-->工厂方法”。

情景分析:假如你有一个Pizza店,那么你的Pizza订单可能会写成如下代码(这段代码写在PizzaStore类里面):

 1 public  Pizza OrderPizza()
 2          {
 3            Pizza pizza = new Pizza();
 4            pizza.Prepare();
 5            pizza.Bake();
 6            pizza.Cut();
 7            pizza.Box();
 8            return pizza;
 9        }

10

如果你的Pizza店的Pizza有很多类,那么你的Pizza订单会如何写呢,可能会写成如下:

 1 class  PizzaStore
 2      {
 3        public Pizza OrderPizza(String paramPizzaType)
 4        {
 5            Pizza pizza = null;
 6            if (paramPizzaType.Equals("cheese"))
 7            {
 8                pizza = new CheesePizza();
 9            }

10            else if (paramPizzaType.Equals("greek"))
11            {
12                pizza = new GreekPizza();
13            }

14            else if (paramPizzaType.Equals("pepperon"))
15            {
16                pizza = new PepperoniPizza();
17            }

18            pizza.Prepare();
19            pizza.Bake();
20            pizza.Cut();
21            pizza.Box();
22            return pizza;
23        }

24
25        // 省略        
26    }

27

 上面的代码有一个问题:当Pizza的种类发生改变(或增加或减少)时,这段代码必须重写。那么这段代码应该如何改进呢?其实我们只要封装变化点就行了,即代码中的“if,else”语句。封装的过程如下:
1)、创建SimplePizzaFactory类。
2)、在SimplePizzaFactory类中创建CreatPizza方法。
3)、把“if,else”语句写道CreatPizza方法中。
相应的代码如下:

 1 public   class  SimplePizzaFactory

 2      {

 3        public Pizza CreatPizza(String paramPizzaType)

 4        {

 5            Pizza pizza = null;

 6            if (paramPizzaType.Equals("cheese"))

 7            {

 8                pizza = new CheesePizza();

 9            }


10            else if (paramPizzaType.Equals("greek"))

11            {

12                pizza = new GreekPizza();

13            }


14            else if (paramPizzaType.Equals("pepperon"))

15            {

16                pizza = new PepperoniPizza();

17            }


18            return pizza;

19        }


20    }


21

这样做的好处:
1)、可以很好的达到代码重用。如果其他类想得到Pizza,都可以调用SimplePizzaFactory的CreatPizza()方法。
2)、维护方便。如果Pizza的创建需要改变,只需要改变CreatPizza()方法就行了,其他调用的地方不需要发生改变。
值得改进的地方
:可以把CreatPizza()写成静态方法。
改成静态方法的优点:不需要通过创建对象来使用类里的方法。
缺点:不能通过继承来改变创建对象的行为。
小结:
上面的代码其实是简单工厂模式的应用(简单工厂不是一个真正的模式)。
简单工厂(Simple Factory)模式的意图:Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例。通常它返回的类都有一个公共的父类和公共的方法。
结构:

image

工厂类角色Creator (SimplePizzaFactory):工厂类在客户端的直接控制下(Create方法)创建产品对象。
抽象产品角色Product (Pizza):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
具体产品角色ConcreteProduct (CheesePizza, GreekPizza,PepperoniPizza):定义工厂具体加工出的对象。
客户端Client(PizzaStore):负责调用SimplePizzaFactory的Create方法。
其实SimplePizzaFactory的CreatPizza()方法并没有符合面向对象的开闭原则,它没有对修改进行关闭,即当Pizza的种类改变时,这个方法必须重写,只不过改动的工作量减少了,只需要改动一处,其他调用的地方不需要变动而已。

新的需求
1)、Pizza店有了加盟店,加盟店生产Pizza的流程应该一成不变。
2)、每个加盟店可能要提供不同风味的Pizza(比如纽约、芝加哥、加州)。
按照简单工厂的方法,我们可以这样做:创建NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory类。相应的代码如下:

1 NYPizzaFactory nyFactory  =   new  NYPizzaFactory();  //  创建具有纽约风味的Pizza工厂
2             PizzaStore nyStore  =   new  PizzaStore(nyFactory);   //  建立Pizza店,经营纽约风味的Pizza
3             nyStore.OrderPizza( " cheese " );                     //  订购具有纽约风味的CheesePizza

 如果需求不发生改变,那么用简单工厂就已经足够了,但是一旦需求发生了变化,简单工厂就不能适应了。

变化后的需求
1)、有些加盟店采用自创的流程,比如烘烤的做法有些差异(Bake方法改变)、不要切片(Cut方法不要)、采用其他公司的盒子(Box方法改变)等。
2)、Pizza的种类有可能发生改变(或增加或减少)。

我们的做法很简单,具体操作
1)、把SimpleFactory的CreatPizza()方法写回到PizzaStore里面。
2)、抽象PizzaStore,用NYPizzaStore、ChicagoPizzaStore等继承PizzaStore。
3)、具体的PizzaStore和具体的Pizza进行一一对应。

相应的类图如下(应用了工厂方法模式):

image 

说明:
1)、PizzaStore类是抽象类,相当于工厂方法模式的Creator类,NYPizzaStore类和ChicagoPizzaStore类继承了PizzaStore,相当于工厂方法模式的ConcreteCreator。
2)、Pizza是抽象类,相当于Product类,NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类、ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类继承了Pizza类,相当于ConcreteProduct。
3)、NYPizzaStore类调用了NYStyleCheesePizza类、NYStylePepperoniPizza类、NYStyleGreekPizza类,ChicagoPizzaStore类调用了ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类。

相应的代码如下:

Code
  1class Program
  2    {
  3        static void Main(string[] args)
  4        {
  5            PizzaStore nyStore = new NYPizzaStore();
  6            PizzaStore chicagoStore = new ChicagoPizzaStore();
  7
  8            Pizza pizza = nyStore.OrderPizza("cheese");
  9            Console.WriteLine("Ethan ordered a " + pizza.GetName());
 10
 11            pizza = chicagoStore.OrderPizza("cheese");
 12            Console.WriteLine("Joel orderd a " + pizza.GetName());
 13
 14            Console.ReadLine();
 15        }

 16    }

 17public class NYPizzaStore : PizzaStore
 18    {        
 19        public override Pizza CreatePizza(String paramPizzaType)
 20        {
 21            Pizza pizza = null;
 22            if (paramPizzaType.Equals("cheese"))
 23            {
 24                pizza = new NYStyleCheesePizza();
 25            }

 26            else if (paramPizzaType.Equals("greek"))
 27            {
 28                pizza = new NYStyleGreekPizza();
 29            }

 30            else if (paramPizzaType.Equals("pepperon"))
 31            {
 32                pizza = new NYStylePepperoniPizza();
 33            }

 34            return pizza;
 35        }

 36    }

 37public class ChicagoPizzaStore : PizzaStore
 38    {
 39        public override Pizza CreatePizza(String paramPizzaType)
 40        {
 41            Pizza pizza = null;
 42            if (paramPizzaType.Equals("cheese"))
 43            {
 44                pizza = new ChicagoStyleCheesePizza();
 45            }

 46            else if (paramPizzaType.Equals("greek"))
 47            {
 48                pizza = new ChicagoStyleGreekPizza();
 49            }

 50            else if (paramPizzaType.Equals("pepperon"))
 51            {
 52                pizza = new ChicagoStylePepperoniPizza();
 53            }

 54            return pizza;
 55        }

 56    }

 57public abstract class PizzaStore
 58    {
 59        public abstract Pizza CreatePizza(String paramType);        
 60
 61        public Pizza OrderPizza(String paramType)
 62        {
 63            Pizza pizza = CreatePizza(paramType);
 64            pizza.Prepare();
 65            pizza.Bake();
 66            pizza.Cut();
 67            pizza.Box();
 68            return pizza;
 69        }

 70    }

 71public abstract class Pizza
 72    {
 73        protected string name;    // 名称
 74        protected string sauce;   // 酱料类型
 75        protected string daugh;   // 面团类型
 76        protected List<string> toppings = new List<string>();  // 一套佐料
 77
 78        public void Prepare()
 79        {
 80            Console.WriteLine("Preparing " + name);
 81            Console.WriteLine("Tossing dough  ");
 82            Console.WriteLine("Adding sauce ");
 83            Console.WriteLine("Adding toppings : ");
 84            foreach (string str in toppings)
 85            {
 86                Console.WriteLine("  " + str);
 87            }

 88        }

 89
 90        public virtual void Bake()
 91        {
 92            Console.WriteLine("Bake for 25 minutes at 350 ");
 93        }

 94
 95        public virtual void Cut()
 96        {
 97            Console.WriteLine("Cutting the pizza into diagonal slices ");
 98        }

 99
100        public virtual void Box()
101        {
102            Console.WriteLine("Place pizza in official PizzaStore box");
103        }

104
105        public String GetName()
106        {
107            return name;
108        }

109    }

110public class ChicagoStyleCheesePizza :Pizza
111    {
112        public ChicagoStyleCheesePizza()
113        {
114            name = "Chicago Style Deep Dish Cheese Pizza";
115            daugh = "Extra Thick Crust Dough";
116            sauce = "Plum Tomato Sauce ";
117
118            toppings.Add("Shredded Mizzarella Cheese ");
119        }

120
121        public override void Cut()
122        {
123            Console.WriteLine("Cutting the pizza into squre slices "); // 芝加哥的Pizza切成方形
124        }

125    }

126public class NYStyleCheesePizza:Pizza
127    {
128        public NYStyleCheesePizza()
129        {
130            name = "NY Style Sauce and Cheese Pizza";
131            daugh = "Thin Crust Dough";
132            sauce = "Marinara Sauce ";
133
134            toppings.Add("Grated Regggiano Cheese");
135        }

136    }

工厂方法模式的特点
1)、核心的工厂类不负责所有产品的创建,而是将具体创建工作交给子类去做,可以允许系统在不修改工厂角色的情况下引进新产品。
2)、工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

工厂方法和简单工厂的区别
1)、Factory Method 的核心是一个抽象工厂类,而Simple Factory 把核心放在一个具体类上。
2)、Factory Method 的具体工厂类都有共同的接口,或者有共同的抽象父类。
3)、当系统扩展需要添加新的产品对象时,Factory Method仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而Simple Factory 在添加新产品对象后不得不修改工厂方法,扩展性不好。

参考文献:
《Head.First设计模式》
  吕震宇  设计模式系列

源代码下载:/Files/wxj1020/PizzaStore.rar

转载于:https://www.cnblogs.com/wxj1020/archive/2008/04/09/1143913.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值