创建型设计模式总结
(转载请注明来源 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 }
运行结果为:
原文链接: https://www.cnblogs.com/jerry19880126/archive/2012/08/08/2628321.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/58583
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!