zoukankan      html  css  js  c++  java
  • 工厂模式(C++编码)

    一、工厂模式概念及分类

    工厂模式概念:用一个简单的类来创建实例的过程便称为工厂,用工厂方式代替外部new操作的一种设计模式称为工厂模式。这是一种创建型模式,它提供了一个创建对象的最佳方式。在工厂模式中,我们创建对象时不会对上层暴露创建逻辑,而是通过使用一个共同结构来指向新创建的对象。

    工厂模式分类:简单工厂模式、工厂方法模式、抽象工厂模式。

    意图:定义一个常见对象的接口,让子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。

    问题解决:主要解决接口选择问题。

    解决方法:让其子类实现工厂接口,返回的是一个抽象的产品。

    使用前提:1、编码时不能预见需要创建哪种类的实例(不同的条件下发创建不同实例);2、系统不应依赖于产品类实例如何被创建、组合和表达的细节。

    关键代码:子类执行创建过程。

    优点:1、使代码结构清晰,有效地封装变化,提高拓展性;2、屏蔽产品的具体实现,调用者只关心产品的接口;3、降低耦合度。

    二、各类工厂模式讲解及实现

    1、简单工厂模式

    (1)概述

    简单工厂模式时属于创建型模式,又叫做静态工厂方法模式,简单工厂模式实现由一个工厂对象决定创建出来指定产品类的实例。

    (2)特点

    简单工厂模式由一个工厂类根据传入的参数,动态决定应该创建哪一种产品类实例。简单工厂模式需要在工厂类中作出判断,在创建产品的时候指定响应产品创造。

    (3)类图

    img

    (4)例子

    假设有个工厂能生产出 A、B 两种产品,当客户需要产品的时候明确告知工厂生产哪类产品,工厂需要接收顾客提供的类别信息,当新增产品的时候,工厂内部去添加新产品的生产方式。

    (5)应用说明

    一个工厂,多个产品,产品需要有一个虚基类,通过接收类别参数生产具体产品,利用基类指针指向此对象。

    (6)编码

     1 #include <iostream>
     2  3 enum ProductType
     4 {
     5     PRODUCT_A,
     6     PRODUCT_B
     7 };
     8  9 // 产品基类
    10 class Product
    11 {
    12 public:
    13     virtual void Show() = 0;
    14 };
    15 16 // 产品 A
    17 class ProductA : public Product
    18 {
    19 public:
    20     void Show()
    21     {
    22         std::cout << "Product A." << std::endl;
    23     }
    24 };
    25 26 // 产品 B
    27 class ProductB : public Product
    28 {
    29 public:
    30     void Show()
    31     {
    32         std::cout << "Porduct B." << std::endl;
    33     }
    34 };
    35 36 // 工厂
    37 class Factory
    38 {
    39 public:
    40     Product* Create(int type)
    41     {
    42         switch(type)
    43         {
    44             case PRODUCT_A : return new ProductA; break;
    45             case PRODUCT_B : return new ProductB; break;
    46 47             default : break;
    48         }
    49     }
    50 };
    51 52 int main()
    53 {
    54     Factory *factory = new Factory();
    55 56     factory->Create(PRODUCT_A)->Show();
    57     factory->Create(PRODUCT_B)->Show();
    58 59     return 0;
    60 }

    (7)缺点

    工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了,违背开闭原则。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。

    2、工厂方法模式

    (1)概述

    多个工厂,多个产品,每个产品对应一个工厂,此时工厂和产品都通过虚基类方式构建。

    (2)特点

    定义一个用于创建对象的接口,让子类决定实例化哪一个类。当增加一个新产品时,同时增加一个新工厂。增加新工厂属于扩展,不会修改以前工厂类和产品类的任何代码。可以看过多个独立的简单工厂模式构成了工厂方法模式。工厂方法让类的实例化推迟到子类中进行。

    (3)类图

    img

    (4)例子

    假设现在有 A、B 两种产品,则开两个工厂,工厂 A 负责生产产品 A,工厂 B 负责生产产品 B,客户只知道创建产品的工厂名,而不知道具体的产品名,工厂不需要再接收客户的产品类别,而只去生产产品。

    (5)应用说明

    把简单工厂模式中的工厂类抽象出一个结构,这个接口只有一个创建抽象产品的工厂方法,工厂方法模式解决了简单工厂模式中出现的缺点。

    (6)编码

     1 #include <iostream>
     2  3 // 产品基类
     4 class Product
     5 {
     6 public:
     7     virtual void Show() = 0;
     8 };
     9 10 // 工厂基类
    11 class Factory
    12 {
    13 public:
    14     virtual Product* Create() = 0;
    15 };
    16 17 // 产品 A
    18 class ProductA : public Product
    19 {
    20 public:
    21     void Show()
    22     {
    23         std::cout << "Product A." << std::endl;
    24     }
    25 };
    26 27 // 产品 B
    28 class ProductB : public Product
    29 {
    30 public:
    31     void Show()
    32     {
    33         std::cout << "Porduct B." << std::endl;
    34     }
    35 };
    36 37 // 工厂 A
    38 class FactoryA : public Factory
    39 {
    40 public:
    41     Product* Create()
    42     {
    43         return new ProductA;
    44     }
    45 };
    46 47 // 工厂 B
    48 class FactoryB : public Factory
    49 {
    50 public:
    51     Product* Create()
    52     {
    53         return new ProductB;
    54     }
    55 };
    56 57 int main()
    58 {
    59     FactoryA *factoryA = new FactoryA();
    60     FactoryB *factoryB = new FactoryB();
    61 62     factoryA->Create()->Show();
    63     factoryB->Create()->Show();
    64 65     return 0;
    66 }

    (7)适用场景

    工厂方法模式和简单工厂模式虽然都是通过工厂来创建对象,他们之间最大的不同是——工厂方法模式在设计上完全完全符合开闭原则。适用场景:1、一个类不知道它所需要的对象的类(在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类);2、一个类通过其子类来指定创建哪个对象(在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展);3、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

    (8)具体应用

    • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

    • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

    • 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

    (9)缺点

    每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

    3、抽象工厂模式

    (1)概述

    工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。

    (2)特点

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

    (3)类图

    img

    (4)例子

    假如 A 产品中有 A1 和 A2 两种型号的产品,B 产品中有 B1 和 B2 两种型号的产品,这个时候使用抽象工厂模式,还是开设两家工厂,工厂等级为 1 则负责生产 A1 、B1 型号产品,工厂等级为 2 则负责生产 A2、B2 型号的产品。这样减少了工厂类和产品类在项目中的数量,并完成针对多个产品等级结构的抽象。

    (5)编码

      1 #include <iostream>
      2  
      3 // Product A
      4 class ProductA
      5 {
      6 public:
      7     virtual void Show() = 0;
      8 };
      9  
     10 class ProductA1 : public ProductA
     11 {
     12 public:
     13     void Show()
     14     {
     15         std::cout << "Product A1." << std::endl ;
     16     }
     17 };
     18  
     19 class ProductA2 : public ProductA
     20 {
     21 public:
     22     void Show()
     23     {
     24         std::cout << "Product A2." << std::endl ;
     25     }
     26 };
     27  
     28 // Product B
     29 class ProductB
     30 {
     31 public:
     32     virtual void Show() = 0;
     33 };
     34  
     35 class ProductB1 : public ProductB
     36 {
     37 public:
     38     void Show()
     39     {
     40         std::cout << "Product B1." << std::endl ;
     41     }
     42 };
     43  
     44 class ProductB2 : public ProductB
     45 {
     46 public:
     47     void Show()
     48     {
     49         std::cout << "Product B2." << std::endl ;
     50     }
     51 };
     52  
     53 // Factory
     54 class Factory
     55 {
     56 public:
     57     virtual ProductA* CreateProductA() = 0;
     58     virtual ProductB* CreateProductB() = 0;
     59 };
     60  
     61 class Factory1 : public Factory
     62 {
     63 public:
     64     ProductA* CreateProductA()
     65     {
     66         return new ProductA1();
     67     }
     68  
     69     ProductB* CreateProductB()
     70     {
     71         return new ProductB1();
     72     }
     73 };
     74  
     75 class Factory2 : public Factory
     76 {
     77     ProductA* CreateProductA()
     78     {
     79         return new ProductA2();
     80     }
     81  
     82     ProductB* CreateProductB()
     83     {
     84         return new ProductB2();
     85     }
     86 };
     87  
     88 int main()
     89 {
     90     Factory  *factoryObj1  = new Factory1();
     91     ProductA *productObjA1 = factoryObj1->CreateProductA();
     92     ProductB *productObjB1 = factoryObj1->CreateProductB();
     93  
     94     productObjA1->Show();
     95     productObjB1->Show();
     96  
     97     Factory  *factoryObj2  = new Factory2();
     98     ProductA *productObjA2 = factoryObj2->CreateProductA();
     99     ProductB *productObjB2 = factoryObj2->CreateProductB();
    100  
    101     productObjA2->Show();
    102     productObjB2->Show();
    103  
    104     return 0;
    105 }

    (6)适用场景

    • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。

    • 系统中有多于一个的产品族,而每次只使用其中某一产品族。

    • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。

    • 系统结构稳定,不会频繁的增加对象。

    (7)开闭原则的倾斜性

    在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为开闭原则的倾斜性。开闭原则要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:1、增加产品族——对于增加新的产品族,工厂方法模式很好的支持了开闭原则,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。2、增加新的产品等级结构——对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则。

    正因为抽象工厂模式存在开闭原则的倾斜性,它以一种倾斜的方式来满足开闭原则,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。

    (8)优点

    易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这样就使得改变一个应用的具体工厂变得非常容易,只需要改变具体工厂即可使用不同的产品配置。让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂实现分离,不会出现在客户代码中。

    (9)缺点

    增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

    三、工厂模式的退化过程

    当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

    四、Reference

    1、C++工厂模式分析和总结(阿里云开发者社区):https://developer.aliyun.com/article/761946

    2、工厂模式——这一篇就够了(InfoQ写作平台):https://xie.infoq.cn/article/88c926822394aa1c80847dd2a

    3、23种设计模式全面解析(C语言中文网):http://c.biancheng.net/design_pattern/

  • 相关阅读:
    NSTimer与循环引用
    Swift类实例与循环引用的解决
    Swift运算符函数与自定义运算符
    Swift延迟存储属性
    Swift枚举-相关值与递归枚举
    互斥锁、自旋锁、dispatch_once性能对比
    Swift闭包与简化
    原子属性和使用互斥锁实现的属性的性能对比
    [HDOJ]_PID_1004_Let the Balloon Rise
    [HDOJ]_PID_2087_剪花布条
  • 原文地址:https://www.cnblogs.com/horacle/p/15494358.html
Copyright © 2011-2022 走看看