zoukankan      html  css  js  c++  java
  • 设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)

    创建型设计模式总结

    (转载请注明来源 http://www.cnblogs.com/jerry19880126/

    创建型设计模式包括简单工厂模式,普通工厂模式,抽象工厂模式,建造者模式,原型模式和最简单的单例模式。

    简单工厂模式(Simple Factory)

     

    从UML图中可以看出,工厂是具体的,Product是抽象的,里面的方法Operation是virtual的,它的三个子类是具体的,子类中的Operation覆盖父类的方法Operation,由多态知识可知,运行时将会调用子类的Operation,父类的Operation只是声明的“接口”。

    多态有三个条件:一是父类的virtual,二是子类的覆盖(要求函数名、参数、返回值都要一模一样),三是父类的指针或引用指向子类的对象。前两个条件已经满足,下面关键是讨论第三个条件。

    第三个条件的关键就是Factory了,Factory能根据客户端的请求,生成不同的具体对象,这可以用flag来标识,假定flag = 1时,生成ConcreteProduct1对象;flag = 2时,生成ConcreteProduct2对象。因此,可以在Factory这样写CreateProduct()。

    Product* CreateProduct(flag)

    {

    Switch(flag)

    case 1: return new ConcreateProduct1(); break;

    case 2: return new ConcreateProduct2(); break;

    case 3:…

    }

    在客户端只要用

    Factory f; // 生成factory对象

    f.getProduct(1).Operation();就可以调用ConcreteProduct1的方法了

    f.getProduct(2).Operation();就可以调用ConcreteProudct2的方法了。

    这样说来,相信读者已经明白,其实工厂方法就是根据客户端不同的“要求”,产生不同的具体对象,再利用多态特性,调用相应具体对象的方法。

    下面给出可执行的源代码,与上述例子不尽相同,但思想是一样的,运行结果如下图所示。

    简单工厂模式
     1 #include <iostream>
     2 using namespace std;
     3 
     4 // 简单工厂模式
     5 
     6 // 抽象产品
     7 class AbstractProduct
     8 {
     9 public:
    10     virtual void getProductsName() = 0;
    11 };
    12 
    13 // 具体产品1
    14 class ConcreteProduct1: public AbstractProduct
    15 {
    16 public:
    17     void  getProductsName()
    18     {
    19         cout << "ConcreteProduct1" << endl;
    20     }
    21 };
    22 
    23 
    24 // 具体产品2
    25 class ConcreteProduct2: public AbstractProduct
    26 {
    27 public:
    28     void  getProductsName()
    29     {
    30         cout << "ConcreteProduct2" << endl;
    31     }
    32 };
    33 
    34 
    35 // 具体的工厂(没有抽象工厂)
    36 class ConcreteFactory
    37 {
    38 public:
    39     AbstractProduct* getProductObject(int flag)
    40     {
    41         if(flag == 1)
    42         {
    43             return new ConcreteProduct1();
    44         }
    45         else if(flag == 2)
    46         {
    47             return new ConcreteProduct2();
    48         }
    49         else
    50         {
    51             return 0;
    52         }
    53     }
    54 };
    55 
    56 int main()
    57 {
    58     ConcreteFactory f;
    59     AbstractProduct* p1 = f.getProductObject(1);
    60     AbstractProduct* p2 = f.getProductObject(2);
    61     p1->getProductsName();
    62     p2->getProductsName();
    63     delete p1;
    64     delete p2;
    65     return 0;
    66 }

    运行结果如下:

     

    (普通)工厂模式(Factory)

    与简单工厂模式换汤不换药,只是把工厂也“抽象”了,UML图如下所示:

    从上图可以看出,只不过多出一块抽象工厂而已。抽象工厂提供CreateProduct的虚接口,在ConcreteFactory中实现,为了便于说明问题,这里假定有两个ConcreteFactory,一个是ConcreteFactory1,只生产ConcreteProduct1产品,另一个是ConcreteFactory2,只生产ConcreteProduct2产品。

    以ConcreteFactory1为例,代码框架如下:

    class ConcreateFactory1: public Factory

    {

     Product* CreateProduct()

    {

         return new ConcreteProduct1();

    }

    };

    在客户端用 Factory *f = new ConcreteFactory1(); f->CreateProduct();就可以得到ConcreteProduct1的对象了。

    下面给出可执行的源代码,运行结果的截图放在后面。

    普通工厂模式
     1 #include <iostream>
     2 using namespace std;
     3 
     4 //普通工厂模式
     5 
     6 //抽象产品
     7 class AbstractProduct
     8 {
     9 public:
    10     virtual void getProductName() = 0;
    11 };
    12 
    13 //具体产品1
    14 class ConcreteProduct1: public AbstractProduct
    15 {
    16 public:
    17     void getProductName()
    18     {
    19         cout << "ConcreteProduct1" << endl;
    20     }
    21 };
    22 
    23 //具体产品2
    24 class ConcreteProduct2: public AbstractProduct
    25 {
    26 public:
    27     void getProductName()
    28     {
    29         cout << "ConcreteProduct2" << endl;
    30     }
    31 };
    32 
    33 
    34 //抽象工厂
    35 class AbstractFactory
    36 {
    37 public:
    38     virtual AbstractProduct* getProduct() = 0;
    39 };
    40 
    41 //具体工厂1
    42 class ConcreteFactory1: public AbstractFactory
    43 {
    44 public:
    45     AbstractProduct* getProduct()
    46     {
    47         return new ConcreteProduct1();
    48     }
    49 };
    50 
    51 
    52 //具体工厂2
    53 class ConcreteFactory2: public AbstractFactory
    54 {
    55 public:
    56     AbstractProduct* getProduct()
    57     {
    58         return new ConcreteProduct2();
    59     }
    60 };
    61 
    62 int main()
    63 {
    64     AbstractFactory* f1 = new ConcreteFactory1();
    65     AbstractFactory* f2 = new ConcreteFactory2();
    66     f1->getProduct()->getProductName();
    67     f2->getProduct()->getProductName();
    68     delete f1, f2;
    69     return 0;
    70 }

    运行结果如下:

     

    抽象工厂模式(Abstract Factory)

    抽象工厂又是(普通)工厂模式的升级版,但本质是相同的。观察UML图,可以看到不同的地方在于多了一个抽象产品的类

    ConcreateFactory1只生产ProductA1和ProductB1,即下标带“1”的产品。可以预见,在ConcreteFactory1中的两个方法应该如下:

    AbstractProductA* CreateProductA()

    {

             return new ProductA1();

    }

    AbstractProductB* CreateProductB()

    {

             return new ProductB1();

    }

    ConcreateFactory2中的两个方法类似,只是将最后的下标换成2而已。

    下面给出可以执行的源代码,运行截图放在代码的后面。

    抽象工厂模式
      1 #include <iostream>
      2 
      3 using namespace std;
      4 
      5  
      6 
      7 // 抽象工厂模式
      8 
      9  
     10 
     11 // 抽象产品A
     12 
     13 class AbstractProductA
     14 
     15 {
     16 
     17 public:
     18 
     19          virtual void getProductName() = 0;
     20 
     21 };
     22 
     23  
     24 
     25 // 具体产品A1
     26 
     27 class ConcreteProductA1: public AbstractProductA
     28 
     29 {
     30 
     31 public:
     32 
     33          void getProductName()
     34 
     35          {
     36 
     37                    cout << "ConcreteProductA1" << endl;
     38 
     39          }
     40 
     41 };
     42 
     43  
     44 
     45  
     46 
     47 // 具体产品A2
     48 
     49 class ConcreteProductA2: public AbstractProductA
     50 
     51 {
     52 
     53 public:
     54 
     55          void getProductName()
     56 
     57          {
     58 
     59                    cout << "ConcreteProductA2" << endl;
     60 
     61          }
     62 
     63 };
     64 
     65  
     66 
     67  
     68 
     69 // 抽象产品B
     70 
     71 class AbstractProductB
     72 
     73 {
     74 
     75 public:
     76 
     77          virtual void getProductName() = 0;
     78 
     79 };
     80 
     81  
     82 
     83 // 具体产品B1
     84 
     85 class ConcreteProductB1: public AbstractProductB
     86 
     87 {
     88 
     89 public:
     90 
     91          void getProductName()
     92 
     93          {
     94 
     95                    cout << "ConcreteProductB1" << endl;
     96 
     97          }
     98 
     99 };
    100 
    101  
    102 
    103  
    104 
    105 // 具体产品B2
    106 
    107 class ConcreteProductB2: public AbstractProductB
    108 
    109 {
    110 
    111 public:
    112 
    113          void getProductName()
    114 
    115          {
    116 
    117                    cout << "ConcreteProductB2" << endl;
    118 
    119          }
    120 
    121 };
    122 
    123  
    124 
    125  
    126 
    127 // 抽象工厂
    128 
    129 class AbstractFactory
    130 
    131 {
    132 
    133 public:
    134 
    135          virtual AbstractProductA* getProductA() = 0;
    136 
    137          virtual AbstractProductB* getProductB() = 0;
    138 
    139 };
    140 
    141  
    142 
    143  
    144 
    145 // 具体工厂1
    146 
    147 class ConcreteFactory1: public AbstractFactory
    148 
    149 {
    150 
    151          AbstractProductA* getProductA()
    152 
    153          {
    154 
    155                    return new ConcreteProductA1;
    156 
    157          }
    158 
    159          AbstractProductB* getProductB()
    160 
    161          {
    162 
    163                    return new ConcreteProductB1;
    164 
    165          }
    166 
    167 };
    168 
    169  
    170 
    171 // 具体工厂2
    172 
    173 class ConcreteFactory2: public AbstractFactory
    174 
    175 {
    176 
    177          AbstractProductA* getProductA()
    178 
    179          {
    180 
    181                    return new ConcreteProductA2;
    182 
    183          }
    184 
    185  
    186 
    187          AbstractProductB* getProductB()
    188 
    189          {
    190 
    191                    return new ConcreteProductB2;
    192 
    193          }
    194 
    195 };
    196 
    197  
    198 
    199  
    200 
    201 int main()
    202 
    203 {
    204 
    205          AbstractFactory *f1 = new ConcreteFactory1();
    206 
    207          AbstractFactory *f2 = new ConcreteFactory2();
    208 
    209          f1->getProductA()->getProductName();
    210 
    211          f1->getProductB()->getProductName();
    212 
    213          f2->getProductA()->getProductName();
    214 
    215          f2->getProductB()->getProductName();
    216 
    217          delete f1, f2;
    218 
    219          return 0;
    220 
    221 }

    运行结果如下:

     

    “工厂系列”设计模式总结

    下面总结一下“工厂系列”设计模式,简单工厂模式只有一份抽象的产品,工厂是具体的;(普通)工厂模式的同样也只有一份抽象的产品,但工厂有抽象的了;抽象工厂模式工厂当然是抽象的,但是它独特的地方在于产品至少有两份是抽象的。

    建造者模式(Builder)

    建造者模式包含一个抽象的Builder类,还有它的若干子类——ConcreteBuilder,不用理会UML图上的Product,关键是看Director,Director里面的方法Construct()其实包含了Builder指针或引用的形参,由客户端传入某个ConcreateBuilder对象。Construct(Builder* builder)的方法大致如下:

    Construct(Builder* builder)

    {

             Builder->BuildPartA();

             Builder->BuildPartB();

             …

    }

    由多态性可知,客户端传进来的ConcreteBuilder是谁,就调用谁的方法。

    可执行的源代码如下,运行结果在源代码的后面。

    建造者模式
      1 #include <iostream>
      2 
      3 using namespace std;
      4 
      5  
      6 
      7 // 建造者模式
      8 
      9  
     10 
     11 // 抽象建造者
     12 
     13 class AbstractBuilder
     14 
     15 {
     16 
     17 public:
     18 
     19          virtual void buildPart1() = 0;
     20 
     21          virtual void buildPart2() = 0;
     22 
     23 };
     24 
     25  
     26 
     27  
     28 
     29 //具体建造者1
     30 
     31 class ConcreteBuilder1: public AbstractBuilder
     32 
     33 {
     34 
     35 public:
     36 
     37          void buildPart1()
     38 
     39          {
     40 
     41                    cout << "用A构造第一部分" << endl;
     42 
     43          }
     44 
     45          void buildPart2()
     46 
     47          {
     48 
     49                    cout << "用B构造第二部分" << endl;
     50 
     51          }
     52 
     53 };
     54 
     55  
     56 
     57  
     58 
     59 //具体建造者2
     60 
     61 class ConcreteBuilder2: public AbstractBuilder
     62 
     63 {
     64 
     65 public:
     66 
     67          void buildPart1()
     68 
     69          {
     70 
     71                    cout << "用X构造第一部分" << endl;
     72 
     73          }
     74 
     75          void buildPart2()
     76 
     77          {
     78 
     79                    cout << "用Y构造第二部分" << endl;
     80 
     81          }
     82 
     83 };
     84 
     85  
     86 
     87 // 指挥者,注意其方法的参数是抽象建造者的指针
     88 
     89 class Director
     90 
     91 {
     92 
     93 public:
     94 
     95          void build(AbstractBuilder *builder)
     96 
     97          {
     98 
     99                    builder->buildPart1();
    100 
    101                    builder->buildPart2();
    102 
    103          }
    104 
    105 };
    106 
    107  
    108 
    109 int main()
    110 
    111 {
    112 
    113          Director d;
    114 
    115          d.build(new ConcreteBuilder1());
    116 
    117          d.build(new ConcreteBuilder2());
    118 
    119          return 0;
    120 
    121 }

    运行结果如下:

     

    原型模式(Prototype)

    听起来挺玄乎,其实说穿了,就是深拷贝问题。当一个类中包含了指针,那么这个类一定要显示规定三个东西:拷贝构造函数,重载”=”操作符以及析构函数。如果程序员使用编译器默认产生的这三个函数,那么得到的对象是原来对象的“浅拷贝”,即只是简单拷贝了指针的值(只复制了地址),没有复制指针指向空间的内容。“浅拷贝”只会保留最近的修改结果,而且在析构时容易出现重复析构的错误。

    “深拷贝”是相对浅拷贝的概念说的,深拷贝不是简单的拷贝指针的值(地址),而是重新生成了一个新的空间,这个空间里存放的内容与传入类内容是完全相同的。

    请看下面“浅拷贝”的实例:

    浅拷贝
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5  
     6 
     7 // 原型模式,本质就是深拷贝
     8 
     9  
    10 
    11 // 浅拷贝,这时可以观察到p的地址是一样的,析构的时候因为重复释放同一地址空间,所以
    12 
    13 // 会出错。
    14 
    15 class PrototypeWrong
    16 
    17 {
    18 
    19 private:
    20 
    21          int a;
    22 
    23          int *p; // 有一个指针
    24 
    25 public:
    26 
    27          PrototypeWrong()
    28 
    29          {
    30 
    31                    a = 3;
    32 
    33                    p = new int(2);
    34 
    35          }
    36 
    37          void outputPointerAddress()
    38 
    39          {
    40 
    41                    cout << p << endl;
    42 
    43          }
    44 
    45  
    46 
    47          ~PrototypeWrong()
    48 
    49          {
    50 
    51                    delete p;
    52 
    53          }
    54 
    55 };
    56 
    57  
    58 
    59 int main()
    60 
    61 {
    62 
    63          // 这一部分是错误的原型模式的测试样例
    64 
    65          PrototypeWrong p1;
    66 
    67          PrototypeWrong p2 = p1;
    68 
    69          p1.outputPointerAddress();
    70 
    71          p2.outputPointerAddress();
    72 
    73 }

    运行结果为:

     

    可以看到指针值(地址)是相同的,所以是浅拷贝,程序没有出现“请按任意键继续”的提示,说明程序其实是卡死的,原因是重复析构指针p。

    再看看“深拷贝”的实例:

    原型模式(深拷贝)
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5  
     6 
     7 // 原型模式,本质就是深拷贝
     8 
     9  
    10 
    11 // 深拷贝,正确的原型模式
    12 
    13 class PrototypeRight
    14 
    15 {
    16 
    17 private:
    18 
    19          int a;
    20 
    21          int *p; // 有一个指针
    22 
    23 public:
    24 
    25          PrototypeRight()
    26 
    27          {
    28 
    29                    a = 3;
    30 
    31                    p = new int(2);
    32 
    33          }
    34 
    35  
    36 
    37          // 不使用默认的拷贝构造函数!
    38 
    39          PrototypeRight(const PrototypeRight& obj)
    40 
    41          {
    42 
    43                    a = obj.a;
    44 
    45                    p = new int(*obj.p);
    46 
    47          }
    48 
    49  
    50 
    51          void outputPointerAddress()
    52 
    53          {
    54 
    55                    cout << p << endl;
    56 
    57          }
    58 
    59  
    60 
    61          ~PrototypeRight()
    62 
    63          {
    64 
    65                    delete p;
    66 
    67          }
    68 
    69 };
    70 
    71  
    72 
    73 int main()
    74 
    75 {
    76 
    77          // 这一部分是正确的原型模式的测试样例
    78 
    79         
    80 
    81          PrototypeRight p1;
    82 
    83          PrototypeRight p2 = p1;
    84 
    85          p1.outputPointerAddress();
    86 
    87          p2.outputPointerAddress();
    88 
    89          return 0;
    90 
    91         
    92 
    93 }

    运行结果如下:

     

    可见指针值不同了,说明指向了不同的空间,而且成功显示了“请按任意键继续”的提示符,说明析构也是正常了。但这里的程序还不完整,按照C++的程序风格,还应该重载“=”运算符,这里的练习便留给读者。

    单例模式(Singleton)

    顾名思义,就是保证某个类只有一个实例(对象),这个应用还是很广的,假设腾迅想让用户每次只能用一个QQ登陆,就可以用到这个模式。

     

    这个UML图非常简单,可以说也是所有设计模式中最简单的了,所以在面试中,常常被面试官们问起。

    要使一个类只能生成一个对象,就是要限制使用它的构造函数,即将构造函数定义为private或protected的,然后另辟一个公有方法Instance,在这个方法里检查instance(instance是指向本类的一个指针或引用,这在C++语法中是可以的)是否为空指针,若为空指针,则说明是第一次生成对象,那么操作是允许的,instance = new Singleton(),若指针非空,说明在之前已经有一个对象(实例)了,单例模式不允许再次生成实例,因此直接返回之前生成的对象的地址。

    将instance定义成static变量,就更符合“单例”模式了,因为static变量只有一份,它属于这个类,不属于某个对象。相应的Instance()方法应该也定义成static的,用Singleton::Instance()来调用。注意这里的static方法和变量是必须的,如果函数不是static,则要事先生成对象才能调用Instance,就破坏了“单例”的思想了,如果变量不是static,那么静态函数Instance又不能引用非static变量。

    下面给出可以执行的源程序:

    单例模式
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5  
     6 
     7 // 单例模式
     8 
     9 class Singleton
    10 
    11 {
    12 
    13 private:
    14 
    15          Singleton(){}; // 不允许直接构造其对象
    16 
    17          static Singleton *instance;
    18 
    19  
    20 
    21 public:
    22 
    23          static Singleton* createInstance()
    24 
    25          {
    26 
    27                    if(!instance)
    28 
    29                    {
    30 
    31                             // 对象第一次被创建,允许
    32 
    33                             cout << "创建新对象" << endl;
    34 
    35                             instance = new Singleton();
    36 
    37                    }
    38 
    39                    else
    40 
    41                    {
    42 
    43                             // 请求再次创建对象,不允许
    44 
    45                             cout << "已经创建过对象了,返回原对象" << endl;
    46 
    47                    }
    48 
    49                    return instance;
    50 
    51          }
    52 
    53          void getAddress()
    54 
    55          {
    56 
    57                    cout << "我的地址是 " << instance << endl;
    58 
    59          }
    60 
    61 };
    62 
    63  
    64 
    65 Singleton* Singleton::instance = 0; //在初始化的时候,不能在前面加static了
    66 
    67  
    68 
    69 int main()
    70 
    71 {
    72 
    73          //Singleton s;//报错:无法访问 private 成员(在“Singleton”类中声明)
    74 
    75          Singleton *s1 = Singleton::createInstance();
    76 
    77          s1->getAddress();
    78 
    79  
    80 
    81          cout << endl << endl;
    82 
    83  
    84 
    85          Singleton *s2 = Singleton::createInstance();
    86 
    87          s2->getAddress();
    88 
    89          return 0;
    90 
    91 }

    运行结果为:

     

  • 相关阅读:
    Error: unable to load xmlsec-openssl library
    count(1)、count(*)与count(列名)的执行区别
    Linux下的压缩zip,解压缩unzip命令详解及实例
    linux centos 如何查看操作系统版本信息
    These dependencies were not found: *!!vue-style-loader!css-loader?
    Git如何永久删除某个重要文件文件或文件夹 (包括历史记录) 强制
    LDAP的filter查询详解
    详谈mysqldump数据导出的问题
    GO -- 遍历删除 数组 slice
    mjml强大&&灵活的邮件模版引擎
  • 原文地址:https://www.cnblogs.com/jerry19880126/p/2628321.html
Copyright © 2011-2022 走看看