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

目录

  • [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++设计模式入门

相关推荐
Zane19941 天前
一个 new 就能创建对象,为什么还要拆出单例、工厂、建造者、原型四种模式?
设计模式
怕浪猫2 天前
一行命令复刻爆款视频,我把 Hypit 从安装跑到了出片
人工智能·设计模式·程序员
Zane19942 天前
函数式编程里的函数,其实不是你天天写的那个函数——三大编程范式的边界在哪
设计模式
Zane19944 天前
策略模式现在该不该上?一次讲清楚过度设计和设计不足怎么找平衡
设计模式
她说..4 天前
常见设计模式-模板方法模式
java·spring·设计模式·springboot
xiaofeiyang1504 天前
第六章 · 桥接 — 三支毛笔,画出九种颜色
设计模式
Shadow(⊙o⊙)5 天前
OTOL设计模式 One Thread One Loop
服务器·网络·设计模式
sarasuki5 天前
如何让LLM 能在半夜偷偷打开网易云呢?
人工智能·设计模式·agent
小王师傅665 天前
【设计模式】装饰模式(四):框架源码实战——从 Java I/O 到 Spring 到 MyBatis
java·设计模式
执明wa5 天前
Android RecyclerView 多类型, 多种 Item
android·xml·开发语言·设计模式·android studio