C++设计模式_10_ Prototype 原型模式(小模式,不太常用)

Prototype 原型模式仍然属于“对象创建模式”模式的一种。前面两篇介绍的工厂方法模式和抽象工厂模式的流行程度要远大于Prototype 原型模式和builder构建器模式,后两种由于较为简单,介绍篇幅也会少一些。

文章目录

  • 1. 动机 (Motivation)
  • 2. 代码演示Prototype 原型模式
    • 2.1 Prototype.cpp
    • 2.2 ConcretePrototype.cpp
    • 2.3 Client
  • 3. 模式定义
  • 4. 结构
  • 5. 要点总结
  • 6. 其他参考

1. 动机 (Motivation)

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

与Factory Method工厂方法模式区别就在于“某些结构复杂的对象”,利用深克隆将对象你想要的当前状态取出来,原型就可以实现传入的prototype状态是怎样就能深克隆一个出来,实现状态复杂对象的再现。

结构复杂的界定很难明确界定,使用Prototype 原型模式和Factory Method工厂方法模式的区别就是看是否Factory Method工厂方法模式可以很简便的创建对象,还是需要需要考虑对象复杂的中间状态,又希望保留该状态,如果是后者就使用Prototype 原型模式。实际使用原型模式的场景很少。

Prototype 原型模式解决的问题是与Factory Method工厂方法模式一模一样的,也是有一些细微不同,属于Factory Method工厂方法模式的变体。

2. 代码演示Prototype 原型模式

2.1 Prototype.cpp

在C++设计模式_08_Factory Method工厂方法模式中可以看到Factory Method工厂方法对应的代码,Prototype 原型模式中将以下代码中的2个类合并起来。

//抽象类
class ISplitter{
public:
    virtual void split()=0;
    virtual ~ISplitter(){}
};


//工厂基类
class SplitterFactory{
public:
    virtual ISplitter* CreateSplitter()=0;
    virtual ~SplitterFactory(){}
};

变为以下形式:

//抽象类
class ISplitter{
public:
    virtual void split()=0;
    virtual ~ISplitter(){}
    virtual ISplitter* CreateSplitter()=0;
};

并修改类的名字得到:

Prototype.cpp

//抽象类
class ISplitter{
public:
    virtual void split()=0;
    virtual ISplitter* clone()=0; //通过克隆自己来创建对象
    
    virtual ~ISplitter(){}

};

2.2 ConcretePrototype.cpp

Factory Method工厂方法中FileSplitter2.cpp就变为以下形式:

ConcretePrototype.cpp

//具体类
class BinarySplitter : public ISplitter{
public:
    virtual ISplitter* clone(){
        return new BinarySplitter(*this);
    }
};

class TxtSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new TxtSplitter(*this);
    }
};

class PictureSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new PictureSplitter(*this);
    }
};

class VideoSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new VideoSplitter(*this);
    }
};

在C++中有着最成熟的克隆自己的方法就是拷贝构造函数,也就是上面的new TxtSplitter(*this),前提是你类的拷贝构造函数要写正确。

2.3 Client

Client也就是MainForm则变为:

class MainForm : public Form
{
    ISplitter*  prototype;//原型对象

public:
    
    MainForm(ISplitter*  prototype){
        this->prototype=prototype;
    }
    
	void Button1_Click(){

		ISplitter * splitter=
            prototype->clone(); //克隆原型得到新对象
        
        splitter->split();
                
	}
};

有些人可能会想到将上面的splitter->split();变为删除 ISplitter * splitter=prototype->clone(); //克隆原型,变为prototype->split();,这是不对的,因为原型对象是供克隆的,真正使用的时候需要创建出新的对象,不能一直使用prototype原型对象。

以上即为Prototype 原型模式。

3. 模式定义

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

——《设计模式》GoF

“原型实例”就是在MainForm中的ISplitter* prototype;,这里的“拷贝”是深克隆。

4. 结构

C++设计模式_10_ Prototype 原型模式(小模式,不太常用)_第1张图片

上图是《设计模式》GoF中定义的Prototype 原型模式的设计结构。结合上面的代码看图中最重要的是看其中稳定和变化部分,也就是下图中红框和蓝框框选的部分。

C++设计模式_10_ Prototype 原型模式(小模式,不太常用)_第2张图片

5. 要点总结

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

6. 其他参考

C++设计模式——原型模式

你可能感兴趣的:(#,C++设计模式,原型模式,c++,设计模式)