原型模式:通过一个对象(原型对象)克隆出多个一模一样的对象。
/ 原型模式:通过一个对象(原型模式)克隆出多个一模一样的对象 通过工厂模式演变成原型模式 /
include
using namespace std;
class Monster { public: // 构造函数 Monster(int life, int magic, int attack) : m_life(life) , m_magic(magic) , m_attack(attack) { } // 做父类时析构函数应该为虚函数 virtual ~Monster() { }
// 具体的实现在子类中进行virtual Monster* clone() = 0;
protected: int m_life; // 生命值 int m_magic; // 魔法值 int m_attack; // 攻击力 };
// 亡灵类怪物 class Undead : public Monster { public: // 构造函数 Undead(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A undead monster came into the world.” << endl; } // 拷贝构造函数 Undead(const Undead& el) : Monster(el) { // 初始化类别中注意对父类子对象的初始化 cout << “Calling the copy constructor creates an undead class monster.” << endl; } Monster clone() override { //return new Undead(300, 80, 80); // 创建亡灵类怪物 return new Undead(this); // 触发拷贝构造函数的调用来创建亡灵类怪物 } // …其他代码略 };
// 元素类怪物 class Element : public Monster { public: // 构造函数 Element(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A element monster came into the world.” << endl; } // 拷贝构造函数 Element(const Element& el) : Monster(el) { // 初始化类别中注意对父类子对象的初始化 cout << “Calling the copy constructor creates an element class monster.” << endl; } Monster clone() override { return new Element(this); } // …其他代码略 };
// 机械类怪物 class Mechanic : public Monster { public: // 构造函数 Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A mechanic monster came into the world.” << endl; } // 拷贝构造函数 Mechanic(const Mechanic& el) : Monster(el) { // 初始化类别中注意对父类子对象的初始化 cout << “Calling the copy constructor creates an mechanic class monster.” << endl; } Monster clone() override { return new Mechanic(this); } // …其他代码略 };
void protytype1() { // 创建一只机械类怪物对象作为原型对象以用于克隆目的 Mechanic mechanic(400, 0, 110); // 创建一只元素类怪物对象作为原型对象以用于克隆目的 Monster* element = new Element(200, 80, 100); // 可以直接new,也可以通过工厂模式来创建原型对象
Monster* clone1 = mechanic.clone(); // 使用原型对象克隆出新的机械类怪物对象Monster* clone2 = element->clone(); // 使用原型对象克隆出新的元素类怪物对象// 可以对clone1 clone2所指向的对象进行各种操作(实现具体的业务逻辑)// ...// 释放资源(克隆出来的怪物对象、堆中创建的对象)delete clone1;delete clone2;delete element;
}
<a name="arf9w"></a># 二、引入原型模式<a name="zdCDN"></a>## 2.1 定义定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。简单来说就是通过克隆来创建新的对象实例。<a name="GeWCR"></a>## 2.2 示例代码```cpp#pragma once#include <iostream>using namespace std;class Monster {public:// 构造函数Monster(int life, int magic, int attack): m_life(life), m_magic(magic), m_attack(attack){}// 做父类时析构函数应该为虚函数virtual ~Monster() { }// 具体的实现在子类中进行virtual Monster* clone() = 0;protected:int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力};// 亡灵类怪物class Undead : public Monster {public:// 构造函数Undead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A undead monster came into the world." << endl;}// 拷贝构造函数Undead(const Undead& el): Monster(el){ // 初始化类别中注意对父类子对象的初始化cout << "Calling the copy constructor creates an undead class monster." << endl;}Monster* clone() override{//return new Undead(300, 80, 80); // 创建亡灵类怪物return new Undead(*this); // 触发拷贝构造函数的调用来创建亡灵类怪物}// ...其他代码略};// 元素类怪物class Element : public Monster {public:// 构造函数Element(int life, int magic, int attack): Monster(life, magic, attack){cout << "A element monster came into the world." << endl;}// 拷贝构造函数Element(const Element& el): Monster(el){ // 初始化类别中注意对父类子对象的初始化cout << "Calling the copy constructor creates an element class monster." << endl;}Monster* clone() override{return new Element(*this);}// ...其他代码略};// 机械类怪物class Mechanic : public Monster {public:// 构造函数Mechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mechanic monster came into the world." << endl;}// 拷贝构造函数Mechanic(const Mechanic& el): Monster(el){ // 初始化类别中注意对父类子对象的初始化cout << "Calling the copy constructor creates an mechanic class monster." << endl;}Monster* clone() override{return new Mechanic(*this);}// ...其他代码略};// 没有克隆方法时需要类型转换进行判断来创建对象void globalCreateMonster(Monster* monster){Monster* tempMonster = nullptr;if (dynamic_cast<Undead*>(monster) != nullptr) {tempMonster = new Undead(300, 50, 80);} else if (dynamic_cast<Element*>(monster) != nullptr) {tempMonster = new Element(200, 80, 100);} else if (dynamic_cast<Mechanic*>(monster) != nullptr) {tempMonster = new Mechanic(200, 80, 100);}if (tempMonster != nullptr) {// 实现各种业务逻辑// ....// 不要忘记释放资源delete tempMonster;}}// 有克隆方法时void globalCreateMonster2(Monster* monster){// 根据已有对象直接创建新对象,不需要已有对象所属的类型Monster* tempMonster = monster->clone();// 实现各种业务逻辑// ....// 不要忘记释放资源delete tempMonster;}void protytype2(){// 创建一只元素类怪物Monster* element = new Element(200, 80, 100);globalCreateMonster2(element);delete element;}
2.3 类图
由类图可看出,原型模式的两种角色:
- Prototype(抽象原型类):Monster类
- ConcretePrototype(具体原型类):Undead、Element、Mechanic类
如果对象内部数据比较复杂多变并且在创建对象的时候希望保持对象的当前状态,那么用原型模式显然比用工厂方法模式更合适。
2.4 工厂模式与原型模式的异同点
- 都不需要程序员知道所创建对象所属的类名。
- 工厂方法模式中的createMonster仍旧属于根据类名来生成新对象。
- 原型模式中的clone是根据现有对象来生成新对象。
- 可以把原型模式看成是一种特殊的工厂方法模式。
2.5 原型模式优缺点
- 如果创建的新对象内部数据比较复杂且多变,原型模式创建对象的效率可能会高很多。
- 原型模式不存在额外的等级结构——原型模式不需要额外的工厂类。
- clone接口的实现方法有多种。
- 有些情况下,产品类中存在一个克隆方法也会给开发提供一些明显便利。
