设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)

创建型设计模式总结

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

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

 

简单工厂模式(Simple Factory)

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第1张图片

 

从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图如下所示:

 

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第2张图片

从上图可以看出,只不过多出一块抽象工厂而已。抽象工厂提供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)

 

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第3张图片

抽象工厂又是(普通)工厂模式的升级版,但本质是相同的。观察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 }
复制代码

 

运行结果如下:

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第4张图片

 

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

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

 

建造者模式(Builder)

 

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第5张图片

建造者模式包含一个抽象的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 }
复制代码

 

运行结果如下:

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第6张图片

 

原型模式(Prototype)

 

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第7张图片

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

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

 

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

 

浅拷贝
复制代码
 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 }
复制代码

 

运行结果为:

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第8张图片

 

可以看到指针值(地址)是相同的,所以是浅拷贝,程序没有出现“请按任意键继续”的提示,说明程序其实是卡死的,原因是重复析构指针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登陆,就可以用到这个模式。

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第9张图片

 

这个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 }
复制代码

 

运行结果为:

设计模式——创建型设计模式总结(简单工厂、普通工厂、抽象工厂、建造者、原型和单例)_第10张图片


你可能感兴趣的:(设计模式,delete,Class,UML,iostream,产品)