设计模式-原型模式

一、原型模式的核心概念

原型模式(Prototype Pattern)是一种创建型设计模式,它的核心思想是:用一个已经创建的实例作为原型,通过复制(克隆)这个原型来创建新的对象,而不是通过传统的构造函数新建

这种模式的优势在于:

  1. 避免重复初始化对象的开销(比如对象创建需要复杂的计算、IO 操作、数据库查询等);
  2. 简化对象的创建过程,尤其是当创建对象的条件复杂(比如构造函数参数多、依赖多)时;
  3. 可以动态生成对象,无需提前知道具体类的类型。

原型模式的核心是 克隆方法(clone),根据克隆的深度,又分为:

  • 浅克隆:只复制对象本身和基本类型成员,引用类型成员(如指针、引用)只复制地址,新旧对象共享同一块内存;
  • 深克隆:不仅复制对象本身,还会递归复制所有引用类型成员,新旧对象完全独立。

二、C++ 实现原型模式的核心结构

在 C++ 中实现原型模式,通常需要:

  1. 定义一个抽象原型类(基类),声明纯虚函数 clone()
  2. 具体原型类(子类)继承抽象原型类,实现 clone() 方法(区分浅克隆 / 深克隆);
  3. 通过调用原型对象的 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;
}
代码解释
  1. 核心优化点 :原型对象 goblinPrototype 仅加载一次技能、装备等资源,克隆的新哥布林直接复用这些资源的拷贝,避免重复加载,提升性能;
  2. 差异化处理:克隆后仅修改坐标、血量等少量属性,符合游戏中 "同类型怪物不同位置 / 强度" 的需求;
  3. 深克隆保障:技能、装备等引用类型通过拷贝构造函数重新创建,避免多个怪物共享同一份资源(比如修改一个哥布林的技能,不会影响其他哥布林)。
输出结果
复制代码
原型哥布林(基础模板):
【哥布林】 血量: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) | 
-------------------------
相关推荐
Tinachen881 天前
YonBIP旗舰版本地开发环境搭建教程
java·开发语言·oracle·eclipse·前端框架
liulilittle1 天前
libxdp: No bpffs found at /sys/fs/bpf
linux·运维·服务器·开发语言·c++
hqwest1 天前
码上通QT实战07--主窗体消息栏设计
开发语言·qt·qt事件·主窗体·stackedwidget
hqwest1 天前
码上通QT实战06--导航按钮事件
开发语言·qt·mousepressevent·qfont·qpainter·qlineargradient·setbrush
星火开发设计1 天前
堆排序原理与C++实现详解
java·数据结构·c++·学习·算法·排序算法
shughui1 天前
实现Python多版本共存
开发语言·python·pip
dhdjjsjs1 天前
Day58 PythonStudy
开发语言·python·机器学习
你真的可爱呀1 天前
自定义颜色选择功能
开发语言·前端·javascript
mzhan0171 天前
perl: redhat9, perl-interpreter.rpm 一个包分成很多个小包
开发语言·perl·redhat·rpm