设计模式之原型模式

简单来说,原型模式(Prototype Pattern) 的核心思想就是:"与其从零创建一个新对象,不如直接克隆一个现有的对象。"

想象一下,如果你需要给 10 个不同的部门提供你的身份证副本,有两种方法:

  1. 非原型模式(手动重绘): 你拿出一张白纸,对着身份证,一笔一划地把头像、文字、国徽全部画出来。每办一个业务,你就得重新画一遍。

  2. 原型模式(复印机): 你把身份证(原型)放在复印机上,按下"复印"键(clone)。复印机直接扫描物理特征并产生副本。


1. 不使用原型模式:手动重绘

在这种模式下,客户端(打印店员工)必须知道身份证的所有细节(姓名、号码等),并且每需要一个副本,都要重新调用构造函数并手动设置属性。

复制代码
#include <iostream>
#include <string>

class IDCard {
public:
    std::string name;
    std::string idNumber;
    std::string purpose;

    // 构造函数:模拟"办证"过程,非常麻烦
    IDCard(std::string n, std::string id) : name(n), idNumber(id) {
        std::cout << "[系统] 正在进行繁琐的身份核验、制卡..." << std::endl;
    }
};

// 客户端代码
int main() {
    // 假设我们已经有一个原件了
    IDCard myID("张三", "110101...");

    // 需求:现在需要两个副本,分别给银行和健身房
    // 缺点:你必须手动重复输入所有信息,万一 idNumber 输错一位就麻烦了
    IDCard copy1(myID.name, myID.idNumber); 
    copy1.purpose = "银行开户";

    IDCard copy2(myID.name, myID.idNumber);
    copy2.purpose = "健身房会员";

    return 0;
}

2. 使用原型模式:复印机一键克隆

在这种模式下,身份证类自带一个 clone() 方法。客户端不需要关心身份证里到底有什么,只需要说"给我复印一份"即可。

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

// 抽象原型
class Prototype {
public:
    virtual ~Prototype() {}
    virtual std::unique_ptr<Prototype> clone() const = 0;
    virtual void setPurpose(std::string p) = 0;
    virtual void display() const = 0;
};

// 具体原型:身份证
class IDCard : public Prototype {
private:
    std::string name;
    std::string idNumber;
    std::string purpose;

public:
    IDCard(std::string n, std::string id) : name(n), idNumber(id), purpose("原件") {
        std::cout << "[系统] 正在进行繁琐的身份核验、制卡..." << std::endl;
    }

    // 关键:克隆方法(利用拷贝构造函数)
    std::unique_ptr<Prototype> clone() const override {
        return std::make_unique<IDCard>(*this); 
    }

    void setPurpose(std::string p) override { purpose = p; }
    
    void display() const override {
        std::cout << "姓名:" << name << " | 用途:" << purpose << std::endl;
    }
};

// 客户端代码
int main() {
    // 1. 只有一份原件
    std::unique_ptr<Prototype> myID = std::make_unique<IDCard>("张三", "110101...");

    // 2. 需求:需要副本
    // 优点:无需再次输入姓名和号码,直接克隆,既快又准
    auto copy1 = myID->clone();
    copy1->setPurpose("银行开户");

    auto copy2 = myID->clone();
    copy2->setPurpose("健身房会员");

    copy1->display();
    copy2->display();

    return 0;
}

3. 直观对比总结

特性 不使用原型模式 使用原型模式
创建方式 必须 new 一个具体类。 调用已存在对象的 clone()
依赖程度 高。 必须知道对象的构造函数参数。 低。 只需要知道 clone() 接口。
复杂性 每次创建都要手动重新赋值(容易出错)。 状态自动复制,只需修改差异部分。
性能开销 大。 每次都要跑一遍复杂的构造逻辑。 小。 通常是高效的内存拷贝。
适用场景 对象很简单,属性很少。 对象初始化极慢,或者属性极其复杂。
相关推荐
sarasuki10 小时前
如何让LLM 能在半夜偷偷打开网易云呢?
人工智能·设计模式·agent
小王师傅6614 小时前
【设计模式】装饰模式(四):框架源码实战——从 Java I/O 到 Spring 到 MyBatis
java·设计模式
执明wa16 小时前
Android RecyclerView 多类型, 多种 Item
android·xml·开发语言·设计模式·android studio
sarasuki16 小时前
如何让 Agent 获取更多的能力?插件 / 技能系统
人工智能·设计模式·agent
sarasuki17 小时前
如何让 Agent 安全运行你的命令 :命令分级 + Hook + 读写锁
人工智能·设计模式·agent
Zane199417 小时前
技术不难,为什么项目却越改越不敢动?聊聊复杂系统开发该怎么想
设计模式
geovindu18 小时前
rust: Factory Method Pattern
开发语言·设计模式·rust·工厂方法模式·创建型模式
一木 之林2 天前
第 8 节 C++ 设计模式在 AI 推理 SDK 和 Agent 工具运行时中如何落地
c++·人工智能·设计模式
Zane19942 天前
MVC 三层架构被打上反模式标签?一次账户扣款需求,讲清楚贫血模型和充血模型该怎么选
设计模式
geovindu3 天前
rust:Builder Pattern
开发语言·设计模式·rust·建造者模式