原型模式
1.1 分类
(对象)创建型
1.2 提出问题
希望复制一个状态完全相同的对象。首先,新建一个相同类的对象。 然后,复制所有成员变量。 但是,有时候不知道具体类型,而且成员变量可能是私有的。(从外部复制对象并非总是可行的)
1.3 解决方案
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。即复制已有对象,而无需使代码依赖他们所属的类。
1.4 实现类图
- 原型(Prototype):接口将对克隆方法进行声明。
- 具体原型(Concrete Prototype):类将实现克隆方法。除了将原始对象的数据复制到克隆体中之外,该方法有时还需处理克隆过程中的极端情况,例如克隆关联对象和梳理递归依赖等等。
- 客户端(Client):可以复制实现了原型接口的任何对象。
1.5 示例代码
#include <iostream>
#include <unordered_map>
using std::string;
enum Type {
ROBOT_CAT = 0,
ROBOT_DOG
};
//原型(Prototype)
class Robot {
protected:
string m_prototype_name = "";
float m_stateOfCharge = 0;
public:
Robot() = default;
Robot(string name):m_prototype_name(name) {
}
virtual ~Robot() {}
virtual Robot* clone() const = 0;
virtual void setStateOfCharge(float) = 0;
};
//具体原型(Concrete Prototype)
class RobotCat : public Robot {
private:
float m_CatValue = 0;
public:
virtual ~RobotCat() {}
RobotCat(const RobotCat& robot) {
m_CatValue = robot.m_CatValue;
}
RobotCat(string name, float value) : Robot(name), m_CatValue(value) {
}
virtual Robot* clone() const override {
return new RobotCat(*this);
}
virtual void setStateOfCharge(float value) override {
m_stateOfCharge = value;
std::cout << "--" << m_prototype_name << " 当前电量:" << m_stateOfCharge
<< ",m_CatValue:" << m_CatValue << std::endl;
}
};
//具体原型(Concrete Prototype)
class RobotDog : public Robot {
private:
float m_DogValue = 0;
public:
virtual ~RobotDog() {}
RobotDog(string name, float value) : Robot(name), m_DogValue(value) {
}
virtual Robot* clone() const override {
return new RobotDog(*this);
}
virtual void setStateOfCharge(float value) override {
m_stateOfCharge = value;
std::cout << "--" << m_prototype_name << " 当前电量:" << m_stateOfCharge
<< ",m_DogValue:" << m_DogValue << std::endl;
}
};
//工厂
class CloneFactory {
std::unordered_map<Type, Robot*> m_prototypes;
public:
CloneFactory() {
m_prototypes[ROBOT_CAT] = new RobotCat("机器猫", 5.0);
m_prototypes[ROBOT_DOG] = new RobotDog("机器狗", 8.0);
}
~CloneFactory() {
delete m_prototypes[ROBOT_CAT];
delete m_prototypes[ROBOT_DOG];
}
Robot* createRobot(Type type) {
return m_prototypes[type]->clone();
}
};
//客户端
void clintcode(CloneFactory& cloneFactory) {
std::cout << "克隆机器猫:\n";
Robot* cloneRobot = cloneFactory.createRobot(ROBOT_CAT);
cloneRobot->setStateOfCharge(90);
delete cloneRobot;
cloneRobot = cloneFactory.createRobot(ROBOT_CAT);
cloneRobot->setStateOfCharge(80);
delete cloneRobot;
std::cout << "克隆机器狗:\n";
cloneRobot = cloneFactory.createRobot(ROBOT_DOG);
cloneRobot->setStateOfCharge(75);
delete cloneRobot;
}
int main()
{
CloneFactory cloneFactory;
clintcode(cloneFactory);
}
1.6 举个栗子
克隆形状:生成完全相同的几何对象副本, 同时无需代码与对象所属类耦合。。
1.7 总结
- 可以克隆对象,而无需与它们所属的具体类相耦合。
- 可以克隆预生成原型,避免反复运行初始化代码。
- 缺点:克隆包含循环引用的复杂对象可能会非常麻烦。