解释说明:使用原型实例指定待创建对象的类型,并且通过复制这个原型阿里创建型的对象
UML 结构图:
抽象原型(Prototype):规定了具体原型对象必须实现的clone()方法
具体原型(ConcretePrototype):实现抽象原型类的clone()方法,它是可被复制的对象
访问类:使用具体原型类中的clone()方法来复制新的对象。
浅拷贝:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址
深拷贝:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址
优点:
如果创建新的对象比较复杂,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
简化对象的创建,无需理会创建过程。
可以在程序运行时(对象属性发生了变化)获得一份内容相同的实例,他们之间不会相互干扰。
缺点:
在实现深拷贝时可能需要比较复杂的代码
需要为每一个类配备一个克隆方法,而且该克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
适用场景
如果创建新对象成本较大,可以利用已有的对象进行复制来获得。
如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。相反,如果对象的状态变化很大,或者对象占用的内存很大,那么采用状态模式会比原型模式更好。
需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便
#pragma once
#include <iostream>
#include <string>
/****原型模式 Prototype******/
using namespace std;
// 猴子
class Monkey
{
public:
Monkey() {}
virtual ~Monkey() {}
virtual Monkey* Clone() = 0; // 克隆
virtual void Play() = 0; // 玩耍
};
// 孙悟空
class SunWuKong : public Monkey
{
public:
SunWuKong(string name) { m_strName = name; }
~SunWuKong() {}
// 拷贝构造函数
SunWuKong(const SunWuKong& other)
{
m_strName = other.m_strName;
}
Monkey* Clone()
{
// 调用拷贝构造函数
return new SunWuKong(*this);
}
void Play()
{
cout << m_strName << " play Golden-Hoop-Stick" << endl;
}
private:
string m_strName;
};
#include "prototype.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
int main()
{
// 孙悟空
Monkey* pSWK = new SunWuKong("Qi Tian Da Sheng");
// 克隆猴子猴孙
Monkey* pSWK1 = pSWK->Clone();
Monkey* pSWK2 = pSWK1->Clone();
pSWK1->Play();
pSWK2->Play();
SAFE_DELETE(pSWK1);
SAFE_DELETE(pSWK2);
SAFE_DELETE(pSWK);
getchar();
return 0;
}