• 我想说设计模式之工厂模式


          我把设计模式分为三种:构造型、结构型、行为型。这也是基本的分类,我并没有创新,可能名字跟书本上的不一致,但是意思是一样的。那工厂模式属于哪种设计模式?要回答这个问题,那么我们首先必须对设计模式的分类有所了解。下来,我就简单的区分下这三种分类。

          构造型:就是为了把构造对象和使用对象分离开,为什么要分离开?因为要构造的这个对象比较复杂,而且可能多处需要用。另外单独构造对象,其实是实现了构造过程的封装。

          结构型:结构决定功能,为了实现软件复杂的功能,众多对象需要一个合理的结构。那么就得考虑对象之间的关系。对象之间的关系,包含五种:继承、组合、聚合、关联、依赖。为了记住这些东西,我发挥下想象力。继承恰如父母与子女的亲情关系。组合像人体的五脏六腑和人之间的关系。聚合正如刘关张与刘备集团。关联恰似朋友。依赖仿佛同事。我想说的是这个顺序刚好从耦合性最强到最弱,不是吗?

          行为型:如果说,构造型和结构型是静态的,那么行为型是动态的,它体现了对象之间的协作。

    接下来,我们谈谈工厂模式,如下图:

     1   public class InnerReferenceEndNoteFactory
     2     {
     3 
     4         public static IInnerReference GetInnerReferenceInstance(ReferenceSystem system)
     5         {
     6             if (system == ReferenceSystem.CodeOrder)
     7             {
     8                 return new InnerReferenceCode();
     9             }
    10             else if (system == ReferenceSystem.AuthorYear)
    11             {
    12                 return new InnerReferenceAuthorYear();
    13             }
    14            
    15         }
    16     }
    17     public interface IInnerReference
    18     {
    19         void CreateInnerReference();
    20     }

    代码说明:上面代码实现了一个简单工厂,定义了一个接口,只有一个方法:创建word文中引文。子类 InnerReferenceCode和 InnerReferenceAuthorYear 实现了这个接口具体实现的代码没有贴出来。工厂内部返回了一个恰当的对象,根据 ReferenceSystem作为条件来判断。ReferenceSystem 是word文中引文的编码模式。而编码模式分为两种:1、顺序编码制 2、作者年度制。所谓顺序编码,就是阿拉伯数字,或者罗马数字等与数字顺序相关的。 作者年度制是先按作者排序,然后按年排序,主要考虑到同一作者在不同年度发表论文的情况。

    如何使用该工厂? 直接调用:InnerReferenceEndNoteFactory.GetInnerReferenceInstance(ReferenceSystem.CodeOrder),因为是静态调用,所以我们也可以称静态工厂

    不料,我把前辈们的代码重构成这个样子,现在需求又变了。我们要增加脚注的功能。脚注也要实现类似的功能。 那之前的代码,是直接暴露出if..else的判断,然后直接实现各个分支的功能。那现在还要在此基础上更改吗?如果再增添一个类似的功能,我的if..else不知道要嵌套成什么样子。先说尾注的文中引文编码模式两种,脚注也是这两种,增添新的功能,也是这两种模式。我们该如何写代码呢?理清思路,如果我们用面向过程的思维:第一步判断是脚注还是尾注或者是其它,第二步判断是顺序编码制,还是作者年度制。这样我们的代码可能是这样子:

    if

       if

       else

    else if

       if

       else 

    else

       if

       else

    如果我们想象下,再增添一种编码制,那这棵树的深度继续增加,到时候势必会增加阅读代码的难度,对于接手代码的人无疑会造成心理压力,那别人可能会心里骂你,把代码都写成这样了。说到这里,我并非说过程思维不好,任何技术或者思想都有适用的场景,面向对象的思想,正是解决复杂问题的一种指导思想。接下来,看看我的重构:

     1    public interface IInnerReferenceFactory
     2     {
     3         IInnerReferenceCode GetInnerReferenceCodeInstance();
     4         IInnerReferenceAuthorYear GetInnerReferenceAuthorYearInstance();
     5     }
     6 
     7     public class InnerReferenceFootNoteFactory : IInnerReferenceFactory
     8     {
     9         public IInnerReferenceCode GetInnerReferenceCodeInstance()
    10         {
    11             return new InnerNoteFootRerenceCode();
    12         }
    13 
    14         public IInnerReferenceAuthorYear GetInnerReferenceAuthorYearInstance()
    15         {
    16             throw new NotImplementedException();
    17         }
    18     }
    19 
    20     public class InnerReferenceEndNoteFactory:IInnerReferenceFactory
    21     {
    22         public IInnerReferenceCode GetInnerReferenceCodeInstance()
    23         {
    24             return new InnerReferenceCode();
    25         }
    26         public IInnerReferenceAuthorYear GetInnerReferenceAuthorYearInstance()
    27         {
    28             return new InnerReferenceAuthorYear();
    29         }
    30     }

    代码说明:我的工厂开始变化了,变成了抽象的工厂 IInnerReferenceFactory,这个工厂构造两种规格的对象 IInnerReferenceCode 和 IInnerReferenceAuthorYear,够抽象了吧。现在看看我们的具体工厂:InnerReferenceFootNoteFactory ,这个是尾注工厂,因为它实现了抽象的工厂,所以就得生产两种对象,生产的对象必须要满足特定的规格,比如 new InnerNoteFootRerenceCode 这个对象必须得实现 IInnerReferenceCode这个接口。

    下来看看如何调用:

     1   public override void CreateInnerReference(FieldData fieldData, List<Bibliography> bibliographies, Journal journalStyle, Dictionary<Guid, string> _dict_Computed = null)
     2         {
     3             ReferenceSystem system = journalStyle.General.RefSystem;
     4             var factory = new InnerReferenceFootNoteFactory();
     5 
     6             if (system == ReferenceSystem.CodeOrder)
     7             {
     8                 factory.GetInnerReferenceCodeInstance().CreateInnerReferenceCode(fieldData, bibliographies, journalStyle, _dict_Computed);
     9             }
    10             if (system == ReferenceSystem.AuthorYear)
    11             {
    12                 factory.GetInnerReferenceAuthorYearInstance().CreateInnerReferenceAuthorYear(fieldData, bibliographies, journalStyle);
    13             }
    14         }

    首先,我们得确定实例化哪个工厂,然后根据编码制确定要生成的对象。因为这部分代码是用来实现脚注功能的,所以实例化哪个工厂其实已经很明确了。这就是抽象工厂。那么有人可能注意到了,为什么不使用工厂模式呢?

    我们先来看个图:

    正方形代表:作者年度编码制

    椭圆:顺序编码制

    黑色:尾注

    灰色:脚注

    次灰色:扩展功能

    模式 目前工厂数 增加一个产品族 增加一个产品等级
    工厂 4 +2工厂 +2工厂
    抽象工厂 2 +1工厂 修改2个工厂

     

     

     

     

    从表格可以看出,抽象工厂使用的工厂数比较少,尤其在一个产品族里,产品比较多的情况下,非常适用。

    抽象工厂使用的时候,也是根据条件选择合适的工厂,如果我们把这部分代码用简单工厂封装起来,这时候,我们可以称为工厂的工厂模式

     

     

         

  • 相关阅读:
    可变参数宏
    指针用作传出参数时,需要二级指针
    ubuntu下配置tftp服务以及开发板中通过tftp下载文件
    calloc()函数和malloc()函数
    android 之反编译
    snprintf()函数使用方法
    android 之对话框的使用
    ubuntu su 密码
    android 发短信 调到联系人
    ubuntu 11.10 android ndk awk安装错误修改记
  • 原文地址:https://www.cnblogs.com/wangqiang3311/p/5892472.html
Copyright © 2020-2023  润新知