设计模式之原型模式

简单来说,原型模式(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() 接口。
复杂性 每次创建都要手动重新赋值(容易出错)。 状态自动复制,只需修改差异部分。
性能开销 大。 每次都要跑一遍复杂的构造逻辑。 小。 通常是高效的内存拷贝。
适用场景 对象很简单,属性很少。 对象初始化极慢,或者属性极其复杂。
相关推荐
geovindu6 小时前
rust: Simple Factory Pattern(续)
后端·设计模式·rust·简单工厂模式·创建型模式
喜欢coding的谢同学7 小时前
Go语言常用设计模式基础和实践案例介绍
开发语言·设计模式·golang
sarasuki1 天前
Agent 的记忆有几种?你的名字是?
人工智能·设计模式·agent
geovindu1 天前
rust: Flyweight Pattern
开发语言·后端·设计模式·rust·享元模式·结构型模式
吠品1 天前
箭头函数为什么不能 new
开发语言·javascript·原型模式
沫璃染墨2 天前
《Linux工程实践篇(一):认识设计模式——从日志系统看策略模式》
linux·c++·安全·设计模式·策略模式
十六宿舍2 天前
【软件设计模式-第一课:基础知识了解】
设计模式·架构·面向对象·软件架构
geovindu2 天前
rust: Facade Pattern
开发语言·后端·设计模式·rust·外观模式
怕浪猫2 天前
面试官让我手写一个 Tool Use,我用了 3 种方案
设计模式·面试·程序员
geovindu3 天前
rust: Abstract Factory pattern
开发语言·后端·设计模式·rust·抽象工厂模式