【C++设计模式】第五篇:原型模式(Prototype)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

克隆对象的效率革命


1. 模式定义与用途​

核心思想​

  • 原型模式:通过复制现有对象(原型)来创建新对象,而非通过new构造。
  • 关键用途:
    1.减少初始化开销:适用于创建成本高的对象(如数据库连接)。
    2.动态配置对象:运行时通过克隆生成预设配置的实例。

经典场景​

  • 游戏开发:批量生成相同属性的敌人或道具。
  • 文档编辑:复制带格式的文本段落。

2. 模式结构解析​

UML类图

plaintext 复制代码
+---------------------+          +---------------------+  
|    Prototype        |          |       Client        |  
+---------------------+          +---------------------+  
| + clone(): Prototype|<>------->| - prototype: Prototype  
+---------------------+          +---------------------+  
          ^  
          |  
+---------------------+  
| ConcretePrototype   |  
+---------------------+  
| + clone()           |  
+---------------------+  

角色说明​

  • Prototype:抽象接口,声明克隆方法 clone()
  • ConcretePrototype:具体原型类,实现克隆逻辑。
  • Client:通过调用 clone() 创建新对象。

3. 简单示例:基础克隆实现

cpp 复制代码
#include <memory>  

// 抽象原型接口  
class Enemy {  
public:  
    virtual ~Enemy() = default;  
    virtual std::unique_ptr<Enemy> clone() const = 0;  
    virtual void attack() const = 0;  
};  

// 具体原型:骷髅战士  
class SkeletonWarrior : public Enemy {  
public:  
    std::unique_ptr<Enemy> clone() const override {  
        return std::make_unique<SkeletonWarrior>(*this); // 调用拷贝构造函数  
    }  

    void attack() const override {  
        std::cout << "骷髅战士挥舞骨刀!\n";  
    }  
};  

// 使用克隆  
auto original = std::make_unique<SkeletonWarrior>();  
auto clone = original->clone();  
clone->attack();  // 输出:骷髅战士挥舞骨刀!  

4. 完整代码:原型管理器与深拷贝优化

场景:游戏敌人原型注册与批量生成

cpp 复制代码
#include <iostream>  
#include <unordered_map>  
#include <memory>  
#include <string>  

// 抽象敌人原型  
class Enemy {  
public:  
    virtual ~Enemy() = default;  
    virtual std::unique_ptr<Enemy> clone() const = 0;  
    virtual void spawn() const = 0;  
    virtual void setHealth(int health) = 0;  
};  

// 具体原型:火焰恶魔  
class FireDemon : public Enemy {  
public:  
    FireDemon(int health, const std::string& color)  
        : health_(health), color_(color) {}  

    std::unique_ptr<Enemy> clone() const override {  
        return std::make_unique<FireDemon>(*this);  
    }  

    void spawn() const override {  
        std::cout << "生成" << color_ << "火焰恶魔(生命值:" << health_ << ")\n";  
    }  

    void setHealth(int health) override {  
        health_ = health;  
    }  

private:  
    int health_;  
    std::string color_;  
};  

// 原型管理器(注册表)  
class PrototypeRegistry {  
public:  
    void registerPrototype(const std::string& key, std::unique_ptr<Enemy> prototype) {  
        prototypes_[key] = std::move(prototype);  
    }  

    std::unique_ptr<Enemy> createEnemy(const std::string& key) {  
        auto it = prototypes_.find(key);  
        if (it != prototypes_.end()) {  
            return it->second->clone();  
        }  
        return nullptr;  
    }  

private:  
    std::unordered_map<std::string, std::unique_ptr<Enemy>> prototypes_;  
};  

// 客户端代码  
int main() {  
    PrototypeRegistry registry;  

    // 注册原型  
    registry.registerPrototype("red_demon", std::make_unique<FireDemon>(100, "红色"));  
    registry.registerPrototype("blue_demon", std::make_unique<FireDemon>(80, "蓝色"));  

    // 批量生成敌人  
    auto enemy1 = registry.createEnemy("red_demon");  
    auto enemy2 = registry.createEnemy("blue_demon");  
    auto enemy3 = registry.createEnemy("red_demon");  

    enemy1->spawn();  // 生成红色火焰恶魔(生命值:100)  
    enemy2->spawn();  // 生成蓝色火焰恶魔(生命值:80)  
    enemy3->setHealth(50);  
    enemy3->spawn();  // 生成红色火焰恶魔(生命值:50)  
}  

5. 优缺点分析

优点 ​​缺点
​避免重复初始化复杂对象 需正确处理深拷贝(尤其含指针成员时)
动态添加/删除原型配置 每个类需实现克隆方法,增加代码量
与工厂模式结合扩展性强 对简单对象可能得不偿失

6. 调试与优化策略

调试技巧(VS2022)​​

1.深拷贝验证

  • 在拷贝构造函数中设置断点,观察成员变量是否被正确复制。
  • 使用 内存断点 检测指针成员是否被重复释放。

2.​原型注册表检查

  • 输出注册表的键列表,确认原型是否成功注册。
cpp 复制代码
for (const auto& pair : prototypes_) {  
    std::cout << "已注册原型: " << pair.first << "\n";  
}  

性能优化​

1.原型预初始化

  • 在程序启动时预加载常用原型,减少运行时开销。

2.浅拷贝优化

  • 对只读数据成员使用浅拷贝(需确保生命周期安全)。
cpp 复制代码
class CheapToCopyEnemy : public Enemy {  
private:  
    const Texture* sharedTexture_;  // 只读资源,浅拷贝  
};  
相关推荐
王老师青少年编程5 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【反悔贪心】:种树
c++·算法·贪心·反悔贪心·csp·信奥赛·种树
c++之路5 小时前
C++ 高频易错点
java·jvm·c++
wuminyu5 小时前
专家视角看Java多态性的底层基石vtable(虚函数表)构建过程解析
java·linux·c语言·jvm·c++
charlie1145141916 小时前
现代Qt开发教程(新手篇)1.10——进程
开发语言·c++·qt·学习
qcx236 小时前
Warp源码深度解析(二):自研GPU UI框架——WarpUI的ECH模式与渲染管线
人工智能·ui·设计模式·rust
wj3055853786 小时前
CMake 项目切换 Ninja 构建问题排查记录
c++
汉克老师6 小时前
GESP2025年6月认证C++五级( 第一部分选择题(1-8))
c++·链表·线性筛·最大公约数·gesp5级·gesp五级·埃氏筛
tjl521314_216 小时前
03C++ 定位 new 运算符(Placement new)
开发语言·c++
乐观勇敢坚强的老彭6 小时前
c++信奥循环嵌套讲解
开发语言·c++
十五年专注C++开发6 小时前
Qt实现带多选功能的组合复选框
开发语言·c++·qt·qcombobox