解读设计模式----简单工厂模式(SimpleFactory Pattern),你要什么我就给你什么

本文首发于博客园,地址:http://www.cnblogs.com/beniao/archive/2008/08/09/1263318.html 

一、模式概述

     从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现,学习了此模式可以为后面的很多中模式打下基础。那好,我们就来了解下什么是简单工厂模式?

 

     我们来分析一个现实生活中的案例,每天早晨起床洗唰后是干什么呢?吃早餐(这里只针对在外吃早餐的上班族)、坐车(我是穷人只有坐公交,当然很多有钱人都自己有车,这里不考虑这些)去公司上班、是这样的吗?OK,下面就来分析下吃早餐中的故事,大家先看看下面这个图:

                      

     当我们在买早餐的时候,早餐店里都卖得写什么呢?这点你有注意吗?众多食品摆在那里,你只对营业员说你要何种食品,他便会知道给你拿什么样的食品给你,这说明什么呢?如果用面向对象的思想来理解的话,营业员在这里就充当了一个工厂的角色,他负责根据你的请求返回你需要的食品对象。而这一点正是简单工厂模式的意图。

 

二、模式意图

     简单工厂模式根据提供给他的数据,返回几个可能类中的一个类的实例。

 

三、模式UML图     

     下面是简单工厂模式的示意性UML图:

                

     如上图,简单工厂模式UML我画了两种,详细如下:

     ① 只有一个产品对象的简单工厂模式。 

     ② 带有一个抽象产品对象的简单工厂模式。

 

四、模式参与者

      工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象。

      抽象产品(AbstractProduct)角色: 是工厂模式所创建对象的父类或是共同拥有的接口。可是抽象类或接口。

      具体产品(ConcreteProduct)对象:工厂模式所创建的对象都是这个角色的实例。

 

五、模式实现

     我们通过上面的分析,已经清晰的知道了工厂模式中的各种角色和职责,那工厂模式通过代码是怎么实现的呢?OK,下面将继续分析上面的吃早餐中的故事,做一个简单的示例实现。

     1、首先我们来看看只有一个产品对象的简单工厂模式的实现。其实这很好理解,就当店里只卖一种食品,这里以馒头为例。

 1  ///   <summary>
 2  ///  馒头
 3  ///   </summary>
 4  public   class  SteamedBread
 5  {
 6       ///   <summary>
 7       ///  构造方法
 8       ///   </summary>
 9       public  SteamedBread()
10      { }
11 
12       ///   <summary>
13       ///  销售价格
14       ///   </summary>
15       private   double  price = 0.5 ;
16       public   double  Price
17      {
18           get  {  return  price; }
19           set  { price  =  value; }
20      }
21  }

     

     OK,产品对象建立好了,下面就是创建工厂(Factory)对象了。

 1  ///   <summary>
 2  ///  工厂角色
 3  ///   </summary>
 4  public   class  Factory
 5  {
 6       ///   <summary>
 7       ///  创建一个馒头(SteamedBread)对象
 8       ///   </summary>
 9       ///   <returns></returns>
10       public   static  SteamedBread CreateInstance()
11      {
12           return   new  SteamedBread();
13      }
14  }

 

     此时,客户端可以这样来调用:

1  public   class  Client
2  {
3       public   static   void  Main( string [] args)
4      {
5           // 通过工厂创建一个产品的实例
6          SteamedBread sb  =  Factory.CreateInstance();
7          Console.WriteLine( " 馒头{0}元一个! " , sb.Price);
8      }
9  }

 

     如上就完成了一个简单工厂模式的简单实现,一个产品和一个工厂,工厂负责创建这个产品。但是者种实现有一定的缺陷,为每一种产品创建一个静态方法来完成产品对象的创建,如果有多个产品则需要定义多个静态方法分别返回不同的对象,用设计原则来说的话这样的实现不符合依赖倒置原则(DIP)。如果系统里只有一个单独的产品对象,那么采用这种实现是完全可以的。UML图如下:

                            

 

     2、带抽象产品(AbstractProduct)角色的简单工厂模式实现

     从上面分析中得知,这种实现得为每一种产品创建一个静态方法来完成产品对象的创建。虽然带有简单工厂的性质,但是又好象不能够完全体现出简单工厂模式的意图。简单工厂的意图是:根据提供给他的数据,返回几个可能类中的一个类的实例根据意图出发进行分析,要实现完全满足简单工厂模式意图的程序,也就得根据提供给工厂的数据,让工厂根据这个数据来进行判断,然后返回相应的对象。OK,看看是下面这样的吗?

                          

     示意性代码如下:

 1  ///   <summary>
 2  ///  食品接口----扮演抽象产品角色
 3  ///   </summary>
 4  public   interface  IFood
 5  {
 6       ///   <summary>
 7       ///  每种食品都有销售价格,这里应该作为共性提升到父类或是接口来
 8       ///  由于我们只需要得到价格,所以这里就只提供get属性访问器
 9       ///   </summary>
10       double  price{ get ;}
11  }
12  ------------------------------------------------------------------------------------
13  ///   <summary>
14  ///  馒头
15  ///   </summary>
16  public   class  SteamedBread:IFood
17  {
18       ///   <summary>
19       ///  构造方法
20       ///   </summary>
21       public  SteamedBread()
22      { }
23 
24       public   double  price
25      {
26           get
27          {
28               return    0.5 ;
29          }
30      }
31  }
32  ------------------------------------------------------------------------------------
33  ///   <summary>
34  ///  包子
35  ///   </summary>
36  public   class  SteamedStuffed:IFood
37  {
38       public  SteamedStuffed()
39      { }
40 
41       ///   <summary>
42       ///  销售价格
43       ///   </summary>
44       public   double  price
45      {
46           get
47          {
48               return    0.6 ;   // 0.6元一个
49          }
50      }
51  }
52  ------------------------------------------------------------------------------------
53  ///   <summary>
54  ///  工厂角色
55  ///   </summary>
56  public   class  Factory
57  {
58       ///   <summary>
59       ///  创建一个馒头(SteamedBread)对象
60       ///   </summary>
61       ///   <returns></returns>
62       public   static  IFood CreateInstance( string  key)
63      {
64           if  (key  ==   " 馒头 " )
65          {
66               return   new  SteamedBread();
67          }
68           else
69          {
70               return   new  SteamedStuffed();
71          }
72      }
73  }
74  ------------------------------------------------------------------------------------
75  public   class  Client
76  {
77       public   static   void  Main( string [] args)
78      {
79           // 通过工厂创建一个产品的实例
80          IFood food  =  Factory.CreateInstance( " 馒头 " );
81          Console.WriteLine( " 馒头{0}元一个! " , food.price);
82 
83          food  =  Factory.CreateInstance( " 包子 " );
84          Console.WriteLine( " 包子{0}元一个! " , food.price);
85      }
86  }

 

     此时的设计就已经完全符合简单工厂模式的意图了。顾客(Client)对早餐店营业员(Factory)说,我要“馒头”,于是营业员便根据顾客所提供的数据(馒头),去众多食品中找,找到了然后就拿给顾客。

 

     3、模式的演变实现

     有些情况下Simple Factory可以由抽象产品角色扮演,一个抽象产品类同时是子类的工厂。也就是说,抽象产品角色扮演两种角色和职责,出了基本的定义还还兼任工厂角色的职责,负责产品的创建工作。这里我们在上面的例子基础上适当修改一下OK了,新建立一个抽象类(Evolution):

 1  ///   <summary>
 2  ///  兼任抽象产品角色和工厂角色两种角色
 3  ///   </summary>
 4  public   abstract   class  Evolution
 5  {
 6       ///   <summary>
 7       ///  共性字段
 8       ///   </summary>
 9       private   double  price;
10       public   double  Price
11      {
12           get  {  return  price; }
13           set  { price  =  value; }
14      }
15 
16 
17       public   static  Evolution CreateInstance( string  key)
18      {
19           if  (key  ==   " 馒头 " )
20          {
21               return   new  SteamedBread();
22          }
23           else
24          {
25               return   new  SteamedStuffed();
26          }
27      }
28  }

 

     那现在,具体的产品对象的设计也应该修改了,把原来实现于IFood接口改为继承此抽象类,如下:

 1  public   class  SteamedBread : Evolution
 2  {
 3       public  SteamedBread()
 4      {
 5           this .Price  =   0.5 ;  //在构造方法里初始话属性的值
 6      }
 7  }
 8 
 9  public   class  SteamedStuffed : Evolution
10  {
11       public  SteamedStuffed()
12      {
13           this .Price  =   0.6 ;
14      }
15  }

     

     通过上面的演化,此时客户端的调用如下:

1  public   class  Client
2  {
3       public   static   void  Main( string [] args)
4      {
5          Evolution el  =  Evolution.CreateInstance( " 包子 " );
6          Console.WriteLine( " 包子{0}元一个! " , el.Price);
7      }
8  }

 

     UML草图如下:

                                       

     在实际的开发中,这种演化是很适用的,可以说是一种编程技巧吧。

 

     4、模式的其他演变

     如果系统中只有唯一的一个具体产品对象,那么可以省略抽象产品角色。这一种其实也就是本钱前面的第一种模式实现。

     如果抽象产品角色省略,那么工厂角色就可以与具体产品角色合并。也就是说一个产品类就是自身的工厂。这样把原有三个独立的角色:抽象产品角色、具体产品角色和工厂角色合并为一个,这个类自己负责创建自己的实例。

 

     注:以上演变可以从上面的程序代码中直接修改而来,这里我就不贴代码了。   

 

六、模式优缺点

      工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅"消费"产品。简单工厂模式通过这种做法实现了对责任的分割。

      当产品有复杂的多层等级结构时,工厂类只有自己,以不变应万变,就是模式的缺点。因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

      系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,违背了"开放--封闭"原则(OCP).另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。

 

七、相关模式

      工厂方法模式:每个产品由一个专门的工厂来负责创建。是一种只有唯一一个产品的实现,带有简单工厂的性质。

      抽象工厂模式:大致和工厂方法相同。

      单例模式:单例的实现和上面模式演变中的最后一种很相似,只要把构造器私有便OK。

 

八、参考资料

     Addison-Wesley,1995,p.185. 中文版:《设计模式:可复用的面向对象软件的基础》 李英军等译.

     Alan Sharroway & James r.Trott.中文版:《设计模式精解

     张逸  著《软件设计精要与模式》

 

 

注:原创文章欢迎转载,未经允许请注明出处:http://beniao.cnblogs.com/http://www.cnblogs.com/   作者:Beniao

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值