【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_;  // 只读资源,浅拷贝  
};  
相关推荐
2401_891482174 小时前
多平台UI框架C++开发
开发语言·c++·算法
无敌昊哥战神4 小时前
【LeetCode 257】二叉树的所有路径(回溯法/深度优先遍历)- Python/C/C++详细题解
c语言·c++·python·leetcode·深度优先
Darkwanderor5 小时前
三分算法的简单应用
c++·算法·三分法·三分算法
2401_831920745 小时前
分布式系统安全通信
开发语言·c++·算法
2401_877274246 小时前
从匿名管道到 Master-Slave 进程池:Linux 进程间通信深度实践
linux·服务器·c++
汉克老师6 小时前
GESP5级C++考试语法知识(八、链表(三)循环链表)
c++·约瑟夫问题·循环链表·gesp5级·gesp五级
阿贵---6 小时前
C++中的RAII技术深入
开发语言·c++·算法
PiKaMouse.7 小时前
navigation2-humble从零带读笔记第一篇:nav2_core
c++·算法·机器人
lightqjx7 小时前
【算法】二分算法
c++·算法·leetcode·二分算法·二分模板
Irissgwe8 小时前
进程间通信
linux·服务器·网络·c++·进程间通信