【转】设计模式学习笔记(4)-原型
Prototype模式在创建型模式中属于较不常用的一个模式,但其思想是十分值得学习的,尤其在Javascript中尤其常见,其中可以参考这里。
Prototype这个词在中文翻译成原型,原型的意思就是说有一个原型对象,其它的对象都是这个对象衍生出来的,有点类似于复印的意思。
理解原型的概念很重要,举个实际的例子吧。在Windows中如果我们要新建某种文件,如txt文件,我们会这样做:
在需要建立文件位置处右击选择新建文件即可,这是通常的做法。另外一种方法是利用已有的一个txt文件复制,即:
这两种创建文件的方式有什么不同呢?当我们右键新建是其实系统将自带的某一个txt文件模板复制到当前位置,模板和生成的文件是不一样的。这里类似于直接对new 某个类产生一个对象。
而第二种方式则是利用一个已有的对象生成一个该对象的拷贝(深拷贝),两个对象是完全一样的,对于生成的新文件来说,原来的那个文件就是它的原型。
在面向对象程序设计中,使用原型模式可有效减小子类的数目。对于C++等静态语言来说,利用原型可以实现动态生成类,使得代码更少;而对于Java等动态语言,原型模式则意义不大,因为这些
语言中的类本身就是一个对象(Java中是不是有个Class对象?),可以直接作为参数传给函数。
举个例子吧,当我们复印文件时,需要一张纸作为模板放在复印机中则可以印刷出一模一样的文件。我们使用原型模式类图为:
在上面的类图中,有文件(类),它是一个抽象类,getWidth方法返回文件的宽度,而clone方法则返回该对象的一个深拷贝。它有A5File和A4File两个子类,子类必须重载clone方法。另外还有个Tools抽象类,
这个类有个go方法,子类可以重载该方法以实现特定的动作,如对于Stapler子类来说,do会将文件装订起来;而对于Cutter子类来说则会裁剪文件。
根据这个类生成的代码是十分简单的。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
class File{public: virtual int getWidth() = 0; virtual File* clone() = 0;};class A5File : public File{private: int width;public: A5File(int n):width(n){} int getWidth() { return width; } File* clone() { return new A5File(this->width); }};class A4File : public File{private: int width;public: A4File(int n):width(n){} int getWidth() { return width; } File* clone() { return new A5File(this->width); }}; |
由于对象只有一个width一个属性,实现clone函数时仅仅将新对象的width设置成现有File对象的width即可。然而在实际应用中,拷贝构造函数的编写并不简单,这不是本文所要介绍的内容,因而从简。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class Tools{public: virtual void go(){}};class Stapler : public Tools{private: File* file;public: Stapler(File* file) { this->file = file->clone(); } void go() { cout << "This is the stapler, this is " << this->file->getWidth() << " width!" << endl; }};class Cutter : public Tools{private: File* file;public: Cutter(File* file) { this->file = file->clone(); } void go() { cout << "This is the cutter, this is " << this->file->getWidth() << "width" << endl; }}; |
Tools的子类仅仅打印文件的宽度和实施操作的名称,这里依然是为了简化处理。
在主函数这样写:
|
1
2
|
Tools* tool = new Stapler(new A5File(123));tool->go(); |
结果输出为:
|
1
|
This is the stapler, this is 123 width! |
这里仅仅实现了原型模式最简单的应用。
在实际应用中,往往利用一个关联管理器(在C++中可以使用Map)存储作为原型的对象,这样在以后的编写中可以检索这个管理器以获得新的对象,这一点对于C++等静态语言十分重要。注:在后面的单例模式也可以这样使用。
前面已经提到了,Prototype模式存在的最大问题是拷贝构造函数的编写,并且必须使用深拷贝,C++中并没有提供默认的拷贝构造函数,必须自己编写(Java中的Object类提供了clone方法)。另外创建出的新对象往往并不能直接
使用,这里可以为每个Prototype子类编写初始化函数,由于必须实现clone方法,当子类比较多的时候还是比较麻烦的。
最后我们来看看原型模式的适用性:
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载
- 为了避免创建一个与产品类层次平行的工厂类层次时
- 当一个类的实例只能有几个不同状态组合中的一种时。
值得注意的是第三条,Prototype模式真正发挥其作用是与Composite以及Decorator模式的组合使用,由于这两个模式是通过对象组合以为对象添加新的职能,这样通过Prototype模式可快速生成具有复杂功能的类。
原文链接:http://lecoding.com/articles/110.html
posted on 2013-03-05 13:56 TheKingOfKingFish 阅读(111) 评论(0) 收藏 举报
浙公网安备 33010602011771号