一、原型模式的核心概念
原型模式(Prototype Pattern)是一种创建型设计模式,它的核心思想是:用一个已经创建的实例作为原型,通过复制(克隆)这个原型来创建新的对象,而不是通过传统的构造函数新建。
这种模式的优势在于:
- 避免重复初始化对象的开销(比如对象创建需要复杂的计算、IO 操作、数据库查询等);
- 简化对象的创建过程,尤其是当创建对象的条件复杂(比如构造函数参数多、依赖多)时;
- 可以动态生成对象,无需提前知道具体类的类型。
原型模式的核心是 克隆方法(clone),根据克隆的深度,又分为:
- 浅克隆:只复制对象本身和基本类型成员,引用类型成员(如指针、引用)只复制地址,新旧对象共享同一块内存;
- 深克隆:不仅复制对象本身,还会递归复制所有引用类型成员,新旧对象完全独立。
二、C++ 实现原型模式的核心结构
在 C++ 中实现原型模式,通常需要:
- 定义一个抽象原型类(基类),声明纯虚函数
clone(); - 具体原型类(子类)继承抽象原型类,实现
clone()方法(区分浅克隆 / 深克隆); - 通过调用原型对象的
clone()方法创建新对象。
三、C++ 代码示例
场景背景
在一款 RPG 游戏中,需要生成大量同类型但属性略有差异的怪物(比如 "哥布林""兽人")。每个怪物包含基础属性(血量、攻击力)、技能列表、装备列表等复杂数据,直接通过构造函数创建会重复加载资源(如技能配置、装备模型),性能开销大。
使用原型模式:先创建一个 "原型怪物"(加载好所有基础资源),后续新怪物都通过克隆原型生成,仅修改少量差异化属性(如血量、位置)。
C++ 完整代码实现
cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 技能类(复杂引用类型)
class Skill {
public:
std::string name; // 技能名称
int damage; // 技能伤害
std::string effect; // 技能效果
Skill(std::string n, int d, std::string e) : name(n), damage(d), effect(e) {}
// 拷贝构造函数(深克隆用)
Skill(const Skill& other) {
this->name = other.name;
this->damage = other.damage;
this->effect = other.effect;
}
void show() const {
std::cout << "技能:" << name << "(伤害:" << damage << ",效果:" << effect << ")";
}
};
// 装备类(复杂引用类型)
class Equipment {
public:
std::string type; // 装备类型(武器/护甲)
int defense; // 防御值
int attack; // 攻击值
Equipment(std::string t, int d, int a) : type(t), defense(d), attack(a) {}
// 拷贝构造函数(深克隆用)
Equipment(const Equipment& other) {
this->type = other.type;
this->defense = other.defense;
this->attack = other.attack;
}
void show() const {
std::cout << "装备:" << type << "(防御:" << defense << ",攻击:" << attack << ")";
}
};
// 抽象原型类:怪物原型
class MonsterPrototype {
public:
std::string name; // 怪物名称
int hp; // 血量
int attack; // 基础攻击力
std::vector<Skill*> skills; // 技能列表(引用类型)
std::vector<Equipment*> equipments; // 装备列表(引用类型)
int x, y; // 坐标(差异化属性)
// 构造函数
MonsterPrototype(std::string n, int h, int a) : name(n), hp(h), attack(a), x(0), y(0) {}
// 纯虚克隆函数(深克隆)
virtual MonsterPrototype* clone() = 0;
// 虚析构函数(释放资源)
virtual ~MonsterPrototype() {
for (auto skill : skills) delete skill;
for (auto eq : equipments) delete eq;
}
// 添加技能
void addSkill(Skill* skill) {
skills.push_back(skill);
}
// 添加装备
void addEquipment(Equipment* eq) {
equipments.push_back(eq);
}
// 设置坐标(差异化属性)
void setPosition(int x, int y) {
this->x = x;
this->y = y;
}
// 显示怪物信息
void showInfo() const {
std::cout << "【" << name << "】 血量:" << hp << ",攻击力:" << attack
<< ",坐标:(" << x << "," << y << ")\n";
std::cout << " 技能:";
for (auto skill : skills) {
skill->show();
std::cout << " | ";
}
std::cout << "\n 装备:";
for (auto eq : equipments) {
eq->show();
std::cout << " | ";
}
std::cout << "\n-------------------------\n";
}
};
// 具体原型类:哥布林
class Goblin : public MonsterPrototype {
public:
// 构造函数:初始化哥布林的基础属性和资源
Goblin() : MonsterPrototype("哥布林", 100, 20) {
// 加载技能(模拟从配置文件/资源库加载,仅加载一次)
addSkill(new Skill("重击", 30, "造成击退效果"));
addSkill(new Skill("偷袭", 25, "暴击率+10%"));
// 加载装备(模拟资源加载)
addEquipment(new Equipment("生锈的匕首", 0, 5));
addEquipment(new Equipment("破布甲", 3, 0));
}
// 深克隆实现:复制所有资源,生成新对象
MonsterPrototype* clone() override {
// 1. 创建新的哥布林对象(基础属性拷贝)
Goblin* newGoblin = new Goblin();
newGoblin->name = this->name;
newGoblin->hp = this->hp;
newGoblin->attack = this->attack;
newGoblin->x = this->x;
newGoblin->y = this->y;
// 2. 深克隆技能列表(避免共享资源)
for (auto skill : this->skills) {
newGoblin->addSkill(new Skill(*skill));
}
// 3. 深克隆装备列表
for (auto eq : this->equipments) {
newGoblin->addEquipment(new Equipment(*eq));
}
return newGoblin;
}
};
// 测试代码
int main() {
// 1. 创建原型:哥布林原型(仅加载一次资源)
MonsterPrototype* goblinPrototype = new Goblin();
std::cout << "原型哥布林(基础模板):\n";
goblinPrototype->showInfo();
// 2. 克隆生成多个哥布林,仅修改差异化属性(坐标、血量)
MonsterPrototype* goblin1 = goblinPrototype->clone();
goblin1->setPosition(10, 20);
goblin1->hp = 120; // 精英哥布林,血量更高
std::cout << "克隆哥布林1(精英):\n";
goblin1->showInfo();
MonsterPrototype* goblin2 = goblinPrototype->clone();
goblin2->setPosition(30, 40);
std::cout << "克隆哥布林2(普通):\n";
goblin2->showInfo();
// 3. 释放资源
delete goblinPrototype;
delete goblin1;
delete goblin2;
return 0;
}
代码解释
- 核心优化点 :原型对象
goblinPrototype仅加载一次技能、装备等资源,克隆的新哥布林直接复用这些资源的拷贝,避免重复加载,提升性能; - 差异化处理:克隆后仅修改坐标、血量等少量属性,符合游戏中 "同类型怪物不同位置 / 强度" 的需求;
- 深克隆保障:技能、装备等引用类型通过拷贝构造函数重新创建,避免多个怪物共享同一份资源(比如修改一个哥布林的技能,不会影响其他哥布林)。
输出结果
原型哥布林(基础模板):
【哥布林】 血量:100,攻击力:20,坐标:(0,0)
技能:技能:重击(伤害:30,效果:造成击退效果) | 技能:偷袭(伤害:25,效果:暴击率+10%) |
装备:装备:生锈的匕首(防御:0,攻击:5) | 装备:破布甲(防御:3,攻击:0) |
-------------------------
克隆哥布林1(精英):
【哥布林】 血量:120,攻击力:20,坐标:(10,20)
技能:技能:重击(伤害:30,效果:造成击退效果) | 技能:偷袭(伤害:25,效果:暴击率+10%) |
装备:装备:生锈的匕首(防御:0,攻击:5) | 装备:破布甲(防御:3,攻击:0) |
-------------------------
克隆哥布林2(普通):
【哥布林】 血量:100,攻击力:20,坐标:(30,40)
技能:技能:重击(伤害:30,效果:造成击退效果) | 技能:偷袭(伤害:25,效果:暴击率+10%) |
装备:装备:生锈的匕首(防御:0,攻击:5) | 装备:破布甲(防御:3,攻击:0) |
-------------------------