设计模式之原型模式

简单来说,原型模式(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() 接口。
复杂性 每次创建都要手动重新赋值(容易出错)。 状态自动复制,只需修改差异部分。
性能开销 大。 每次都要跑一遍复杂的构造逻辑。 小。 通常是高效的内存拷贝。
适用场景 对象很简单,属性很少。 对象初始化极慢,或者属性极其复杂。
相关推荐
ZJPRENO9 小时前
吃透软件开发六大设计原则,告别烂代码
设计模式
咖啡八杯9 小时前
GoF设计模式——命令模式
java·设计模式·架构
花椒技术1 天前
HJPusher / HJPlayer SDK 实践:我们为什么把直播推播链路拆成一套可复用能力
设计模式·harmonyos·直播
艺艺生辉1 天前
迭代器模式-"我也想被增强for循环"
设计模式
咖啡八杯3 天前
GoF设计模式——策略模式
java·后端·spring·设计模式
槑有老呆4 天前
别再手搓 Prompt 了,那个叫"手动挡循环"
设计模式
用户6919026813395 天前
Vibe Coding 开发项目的基本范式
人工智能·设计模式·代码规范
怕浪猫6 天前
领域特定语言(Domain-Specific Language, DSL)
设计模式·程序员·架构