“对象创建”模式之原型模式

目录

  • [Prototype 原型模式](#Prototype 原型模式)

Prototype 原型模式

动机 Motivation

  • 在软件系统中,经常面临着"某些结构复杂的对象"的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
  • 如何应对这种变化?如何向"客户程序(使用这些对象的程序)"隔离出"这些易变对象",从而使得"依赖这些易变对象的客户程序"不随着需求改变而改变?

引例

  • 前文中分割器的例子,使用工厂方法模式是一种方式,下面介绍使用原型模式的方式。
cpp 复制代码
// 抽象类
class ISplitter
{
public:
    virtual void split() = 0;
    virtual ISplitter* Clone() = 0;          // 通过克隆自己来创建对象
    virtual ~ISplitter() {}
};

// 具体类 - 二进制分割器
class BinarySplitter : public ISplitter
{
private:
    std::string* binaryData;  // 假设有需要深拷贝的指针成员
    int dataSize;
    
public:
    BinarySplitter() : binaryData(nullptr), dataSize(0) {}
    
    // 深拷贝构造函数
    BinarySplitter(const BinarySplitter& other) 
        : dataSize(other.dataSize)
    {
        if (other.binaryData != nullptr) 
        {
            binaryData = new std::string(*other.binaryData);
        } else 
        {
            binaryData = nullptr;
        }
    }
    
    ~BinarySplitter() 
    {
        delete binaryData;
    }
    
    void setData(const std::string& data) 
    {
        if (binaryData == nullptr) 
        {
            binaryData = new std::string(data);
        } else 
        {
            *binaryData = data;
        }
    }
    
    virtual void split() override 
    {
        std::cout << "Splitting binary data: " << (binaryData ? *binaryData : "") << std::endl;
    }
    
    virtual ISplitter* Clone() override 
    {
        return new BinarySplitter(*this);  // 调用拷贝构造函数进行深拷贝
    }
};

// 具体类 - 图片分割器
class PictureSplitter : public ISplitter
{
private:
    std::string* imageData;  // 假设有需要深拷贝的指针成员
    int width, height;
    
public:
    PictureSplitter() : imageData(nullptr), width(0), height(0) {}
    
    // 深拷贝构造函数
    PictureSplitter(const PictureSplitter& other) 
        : width(other.width), height(other.height)
    {
        if (other.imageData != nullptr) 
        {
            imageData = new std::string(*other.imageData);
        } else 
        {
            imageData = nullptr;
        }
    }
    
    ~PictureSplitter() 
    {
        delete imageData;
    }
    
    void setImage(const std::string& data, int w, int h) 
    {
        if (imageData == nullptr) 
        {
            imageData = new std::string(data);
        } else 
        {
            *imageData = data;
        }
        width = w;
        height = h;
    }
    
    virtual void split() override 
    {
        std::cout << "Splitting picture (" << width << "x" << height 
                  << "): " << (imageData ? imageData->substr(0, 10) + "..." : "") << std::endl;
    }
    
    virtual ISplitter* Clone() override 
    {
        return new PictureSplitter(*this);  // 调用拷贝构造函数进行深拷贝
    }
};

// 具体类 - 视频分割器
class VideoSplitter : public ISplitter
{
private:
    std::string* videoData;  // 假设有需要深拷贝的指针成员
    double duration;
    
public:
    VideoSplitter() : videoData(nullptr), duration(0) {}
    
    // 深拷贝构造函数
    VideoSplitter(const VideoSplitter& other) 
        : duration(other.duration)
    {
        if (other.videoData != nullptr) 
        {
            videoData = new std::string(*other.videoData);
        } else 
        {
            videoData = nullptr;
        }
    }
    
    ~VideoSplitter() 
    {
        delete videoData;
    }
    
    void setVideo(const std::string& data, double dur) 
    {
        if (videoData == nullptr) 
        {
            videoData = new std::string(data);
        } else 
        {
            *videoData = data;
        }
        duration = dur;
    }
    
    virtual void split() override 
    {
        std::cout << "Splitting video (" << duration 
                  << "s): " << (videoData ? videoData->substr(0, 10) + "..." : "") << std::endl;
    }
    
    virtual ISplitter* Clone() override 
    {
        return new VideoSplitter(*this);  // 调用拷贝构造函数进行深拷贝
    }
};

// MainForm
class MainForm
{
    ISplitter* prototype;
    
public:
    MainForm(ISplitter* prototype)          // 通常由外部传入
    {
        this->prototype = prototype;
    }
    
    ~MainForm() 
    {
        delete prototype;
    }
    
    void Button1_Click()
    {
        ISplitter* splitter = prototype->Clone();     // 克隆原型    
        splitter->split();
        delete splitter;
    }
};

int main() 
{
    // 创建原型对象
    BinarySplitter* binaryProto = new BinarySplitter();
    binaryProto->setData("Sample binary data");
    
    // 使用原型
    MainForm form1(binaryProto);
    form1.Button1_Click();
    
    // 另一个例子
    PictureSplitter* pictureProto = new PictureSplitter();
    pictureProto->setImage("Very long picture data...", 1920, 1080);
    
    MainForm form2(pictureProto);
    form2.Button1_Click();
    
    return 0;
}

模式定义

使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

结构 Structure

前文代码中的ISplitter对应图中的Prototype;BinarySplitter对应ConcretePrototype1,VideoSplitter对应ConcretePrototype2;MainForm对应Client

要点总结

  • Prototype原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有"稳定的接口"。
  • 原型模式对于"如何创建易变类的实体对象"采用"原型克隆"的方法来做,它使得我们可以非常灵活地动态创建"拥有某些稳定接口"的新对象------所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方Clone。
  • 原型模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。

来源:极客班------C++设计模式入门

相关推荐
博风4 小时前
7、设计模式应用举例:策略模式:加密、解密文件
设计模式·策略模式
4SAPI4 小时前
Provider Adapter设计模式:如何让AI应用支持多个模型
网络·人工智能·设计模式
geovindu6 小时前
rust: pool Pattern
开发语言·后端·设计模式·rust·对象池简写模式
高晶6 小时前
ARM 嵌入式 Linux 开发:从体系结构到 LED 点亮实战
设计模式·程序员
VimorphTech7 小时前
接入两套 TTS 接口后,业务代码如何避免堆满 if/else?
设计模式
geovindu9 小时前
rust: pool Pattern (续)
开发语言·后端·设计模式·rust·对象池简写模式
2302_805771071 天前
Day23:POM设计模式(封装)
java·开发语言·设计模式
范中勤2 天前
技术文档:模型工厂 `llm_provider` / `llm_use` 分层设计
设计模式·langchain·架构设计·模型工厂·llm_provider
浅尝辄止;2 天前
设计模式在HIS/LIS医疗系统中的完整实践指南(C#版)
开发语言·设计模式·c#
范中勤2 天前
适配器模式(Adapter Pattern):原理、场景与 LLM 多厂商工程落地
设计模式·架构·langchain·适配器模式·多厂商