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

目录

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

相关推荐
码农秋15 分钟前
设计模式系列(10):结构型模式 - 桥接模式(Bridge)
设计模式·桥接模式
GodKeyNet16 分钟前
设计模式-桥接模式
java·设计模式·桥接模式
N_NAN_N6 小时前
类图+案例+代码详解:软件设计模式----原型模式
java·设计模式·原型模式
缘来是庄7 小时前
设计模式之组合模式
java·设计模式·组合模式
DKPT7 小时前
Java组合模式实现方式与测试方法
java·笔记·学习·设计模式·组合模式
鼠鼠我呀27 小时前
【设计模式09】组合模式
设计模式·组合模式
N_NAN_N9 小时前
类图+案例+代码详解:软件设计模式----单例模式
java·单例模式·设计模式
尤物程序猿9 小时前
设计模式之代理模式--数据库查询代理和调用日志记录
设计模式·代理模式
GodKeyNet19 小时前
设计模式-模板模式
设计模式·模板模式
缘来是庄1 天前
设计模式之建造者模式
java·设计模式·建造者模式