定义:原型模式(Prototype Pattern),用原型模式指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
类型:创建型模式。
类图:
参与角色:
- CPrototype,抽象原型基类,提供一个Clone的接口以及一些设置显示的接口。
- CConcretePrototype,声明定义原型的相关参数,并实现Clone接口,主要是通过实现拷贝构造函数来完成的。
另外实现其他接口。
- Client,首先定义一个原型对象,然后以此为原型克隆新的对象。
概述:
如果只是为了更快的完成新对象的生成,其实就没必要使用原型模式了。因为可以直接使用拷贝构造函数即可。而使用原型模式最重要的原因是隔离Client去了解具体的实现类,降低模块间的耦合。Client只需要知道一个抽象类的指针,不仅可以操作具体各咱方法,另外也还可以生成新的对象。
另外,使用拷贝构造函数时,需要注意深拷贝及浅拷贝。浅拷贝,即按位进行拷贝,即两个对象的每一个成员变量是相同的。深拷贝,自定义拷贝,一般会处理指针,引用等类型,保证它们有相同的值,而不是它们本身相同。
有一批Thinkpad电脑,除了内存和硬盘容量外,其他配置都相同。我们可以通过原型对象生成新的对象,并且不需要知道具体的实现类名。
// 提供接口
1 class CPrototype 2 3 { 4 5 public: 6 7 virtual CPrototype* Clone() = 0; 8 9 virtual void Show() = 0; 10 11 virtual void SetRam(int _nRam) = 0; 12 13 virtual void SetRom(int _nRom) = 0; 14 15 };
// 电脑的基本配置信息类
1 class CComputerConfig : public CPrototype 2 3 { 4 5 public: 6 7 CComputerConfig(char* _szName, int _nRomSize, int _nRamSize) : m_nRomSize(_nRomSize), m_nRamSize(_nRamSize) 8 9 { 10 11 if (NULL != _szName) 12 13 { 14 15 size_t nSize = strlen(_szName) + 1; 16 17 m_szComputerName = new char[nSize]; 18 19 strcpy_s(m_szComputerName, nSize, _szName); 20 21 } 22 23 else 24 25 { 26 27 m_szComputerName = NULL; 28 29 } 30 31 } 32 33 34 35 ~CComputerConfig() 36 37 { 38 39 if (NULL != m_szComputerName) 40 41 { 42 43 delete m_szComputerName; 44 45 } 46 47 } 48 49 50 51 CComputerConfig(const CComputerConfig& _other) 52 53 { 54 55 if (NULL == _other.m_szComputerName) 56 57 { 58 59 m_szComputerName = NULL; 60 61 } 62 63 else 64 65 { 66 67 size_t nSize = strlen(_other.m_szComputerName) + 1; 68 69 m_szComputerName = new char[nSize]; 70 71 strcpy_s(m_szComputerName, nSize, _other.m_szComputerName); 72 73 74 75 m_nRomSize = _other.m_nRomSize; 76 77 m_nRamSize = _other.m_nRamSize; 78 79 } 80 81 } 82 83 84 85 virtual CPrototype* Clone() 86 87 { 88 89 return new CComputerConfig(*this); 90 91 } 92 93 94 95 virtual void Show() 96 97 { 98 99 cout<<m_szComputerName<<",Ram "<<m_nRamSize<<",Rom "<<m_nRomSize<<endl; 100 101 } 102 103 104 105 virtual void SetRam(int _nRam) 106 107 { 108 109 m_nRamSize = _nRam; 110 111 } 112 113 114 115 virtual void SetRom(int _nRom) 116 117 { 118 119 m_nRomSize = _nRom; 120 121 } 122 123 public: 124 125 char* m_szComputerName; 126 127 int m_nRomSize; 128 129 int m_nRamSize; 130 131 }; 132 133
// 客户端
1 int _tmain(int argc, _TCHAR* argv[]) 2 3 { 4 5 // ThindPad系列电脑 6 7 CComputerConfig computer("Thinkpad", 500, 2); 8 9 10 11 // 原型 12 13 CPrototype* pPrototype = &computer; 14 15 pPrototype->Show(); 16 17 18 19 // ThindPad系列的2G内存版,500G硬盘版 20 21 CPrototype* p2GComputer = computer.Clone(); 22 23 p2GComputer->SetRam(4); 24 25 p2GComputer->Show(); 26 27 28 29 // 4G内存,1T硬盘版 30 31 CPrototype* p1TCompter = computer.Clone(); 32 33 p1TCompter->SetRam(8); 34 35 p1TCompter->SetRom(1024); 36 37 p1TCompter->Show(); 38 39 40 41 return 0; 42 43 } 44 45
使用场合:
- 两个模块A,B,模块B对外暴露一个对象C指针。而模块A需要建立很多很多C的对象,但是不需要知道具体的C是如何创建的。这个时候就应该使用原型模式。
优缺点:
- 优点,能够降低模块间的耦合性,另外能够快速的创建新对象。
缺点,改造一个已有类型时,需要细心考虑所有成员变量拷贝的问题,容易遗漏造成错误。
参考资料:
- 《设计模式——可复用面向对象软件基础》
- 《Java与模式》
- 《大话设计模式》