设计模式之原型模式

简单来说,原型模式(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() 接口。
复杂性 每次创建都要手动重新赋值(容易出错)。 状态自动复制,只需修改差异部分。
性能开销 大。 每次都要跑一遍复杂的构造逻辑。 小。 通常是高效的内存拷贝。
适用场景 对象很简单,属性很少。 对象初始化极慢,或者属性极其复杂。
相关推荐
老码观察3 小时前
设计模式实战解读(九):责任链模式——流水线上层层把关的艺术
java·设计模式·责任链模式
J2虾虾1 天前
Spring AI Alibaba - 检索增强生成(RAG)
人工智能·spring·原型模式
workflower2 天前
具身智能研究对象:物理交互中的智能行为
设计模式·动态规划·软件工程·软件构建·scrum
折哥的程序人生 · 物流技术专研2 天前
Java 23 种设计模式:从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建?跨平台 UI 如何一键换肤?
java·开发语言·后端·设计模式
老码观察2 天前
设计模式实战解读(八):代理模式——控制访问的隐形中间层
设计模式·代理模式
我爱cope2 天前
【Agent智能体12 | 反思设计模式-使用外部反馈】
人工智能·设计模式·语言模型·职场和发展
geovindu2 天前
python: Bounded Parallelism Pattern
开发语言·python·设计模式·有界并行模式
我爱cope2 天前
【Agent智能体11 | 反思设计模式-评估反射的影响的方法】
人工智能·设计模式·语言模型·职场和发展
nnsix2 天前
设计模式 - 迭代器模式 笔记
笔记·设计模式·迭代器模式
geovindu2 天前
go: Bounded Parallelism Pattern
开发语言·后端·设计模式·golang·有界并行模式