Prototype 模式也正是提供了自我复制的功能, 就是说新对象的创建可以通过已有对象进行创建。在 C++中,拷贝构造函数( Copy Constructor) 曾经是很对程序员的噩梦,浅层拷贝和深层拷贝的魔魇也是很多程序员在面试时候的快餐和系统崩溃时候的根源之一。
在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。
UML类图
由于克隆需要一个原型,而上面的类图中Prototype就这个原型,Prototype定义了克隆自身的Clone接口,由派生类进行实现,而实现原型模式的重点就在于这个Clone接口的实现。ConcretePrototype1类和ConcretePrototype2类继承自Prototype类,并实现Clone接口,实现克隆自身的操作;同时,在ConcretePrototype1类和ConcretePrototype2类中需要重写默认的复制构造函数,供Clone函数调用,Clone就是通过在内部调用重写的复制构造函数实现的。在后续的编码过程中,如果某个类需要实现Clone功能,就只需要继承Prototype类,然后重写自己的默认复制构造函数就好了。好比在C#中就提供了ICloneable接口,当某个类需要实现原型模式时,只需要实现这个接口的道理是一样的。
使用场合
原型模式和建造者模式、工厂方法模式一样,都属于创建型模式的一种。简单的来说,我们使用原型模式,就是为了创建对象。不过,适合原型模式的最好选择如下:
1.当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象比较容易一些;
2.有的时候,我们需要一个对象在某个状态下的副本,此时,我们使用原型模式是最好的选择;例如:一个对象,经过一段处理之后,其内部的状态发生了变化;这个时候,我们需要一个这个状态的副本,如果直接new一个新的对象的话,但是它的状态是不对的,此时,可以使用原型模式,将原来的对象拷贝一个出来,这个对象就和之前的对象是完全一致的了;
3.当我们处理一些比较简单的对象时,并且对象之间的区别很小,可能就几个属性不同而已,那么就可以使用原型模式来完成,省去了创建对象时的麻烦了;
4.有的时候,创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程。
->适当的时候考虑一下原型模式,能减少对应的工作量,减少程序的复杂度,提高效率。
代码实现:
1 // clone.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include<string> 7 using namespace std; 8 9 class Prototype 10 { 11 public: 12 Prototype(string str) 13 { 14 str_ = str; 15 } 16 Prototype() 17 { 18 str_ = ""; 19 } 20 void show() 21 { 22 cout<<str_<<endl; 23 } 24 virtual Prototype *clone() = 0; 25 private: 26 string str_; 27 }; 28 29 class ConcretePrototype1:public Prototype 30 { 31 public: 32 ConcretePrototype1(string s):Prototype(s){} 33 ConcretePrototype1(){} 34 virtual Prototype *clone() 35 { 36 ConcretePrototype1 *p = new ConcretePrototype1(); 37 *p = *this; 38 return p; 39 } 40 }; 41 class ConcretePrototype2:public Prototype 42 { 43 public: 44 ConcretePrototype2(string s):Prototype(s){} 45 ConcretePrototype2(){} 46 virtual Prototype *clone() 47 { 48 ConcretePrototype2 *p = new ConcretePrototype2(); 49 *p = *this; 50 return p; 51 } 52 }; 53 54 int _tmain(int argc, _TCHAR* argv[]) 55 { 56 cout<<"原型模式"<<endl; 57 ConcretePrototype1 *test = new ConcretePrototype1("小李"); 58 test->show(); 59 ConcretePrototype2 *test2 = (ConcretePrototype2 *)test->clone(); 60 test2->show(); 61 system("pause"); 62 return 0; 63 }
1 // clonejianli.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include <string> 7 8 using namespace std; 9 class Resume 10 { 11 private: 12 string name; 13 string sex; 14 string age; 15 string timeArea; 16 string company; 17 public: 18 Resume(string s) 19 { 20 name = s; 21 } 22 void setPersonalInfo(string s,string a) 23 { 24 sex = s; 25 age = a; 26 } 27 void setWorkExperience(string t,string c) 28 { 29 timeArea = t; 30 company = c; 31 } 32 void Display() 33 { 34 cout<<name<<" "<<sex<<" "<<age<<endl; 35 cout<<"工作经历: "<<timeArea<<" "<<company<<endl<<endl; 36 } 37 Resume *clone() 38 { 39 Resume *b; 40 b = new Resume(name); 41 b->setPersonalInfo(sex,age); 42 b->setWorkExperience(timeArea,company); 43 return b; 44 } 45 }; 46 47 int _tmain(int argc, _TCHAR* argv[]) 48 { 49 Resume *r=new Resume("李俊宏"); 50 r->setPersonalInfo("男","26"); 51 r->setWorkExperience("2007-2010","读研究生"); 52 r->Display(); 53 Resume *r2 = r->clone(); 54 r2->setWorkExperience("2003-2007","读本科"); 55 r2->Display(); 56 system("pause"); 57 return 0; 58 }