设计模式之原型模式(C++)

1.作用

可以对对象进行动态隐藏的复制。例如在程序中需要生成某个状态下对象的副本时可以使用该模式。 有人会说利用类的拷贝构造函数也可以达到这样是效果,的确如此,但拷贝构造达不到隐藏的效果。

四人书中定义的意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
核心: 用原型实例指定创建对象的种类。
利用拷贝构造函数拷贝对象时,我们必须提供待被复制具体的对象,确切的说我们必须知道具体的实例,例如:

2.UML视图

原型模式类静态关系图
- Prototype(抽象原型):原型基类,主要是为了定义了克隆自身的接口。
- ConcretePrototype(具体原型):被复制的对象,需要实现 Prototype 定义的接口,即拷贝构造函数。
- Client(用户):用户利用原型接口得到拷贝对象。

3.实现

举例:动物园有一只高端山羊,今年2岁了,研究所需要对这个年龄的这种羊展开研究,这个任务落到你头上了,假设时间不限,方案有如下三个:
- 从动物抱一只此山羊的羔羊,培养两年交货。—new 一个具体对象,再进行赋值。
- 从动物把这只羊迁到某魔术中心变一只一模一样的(假设可以)。—利用对象拷贝构造函数创建具体对象,需要提供具体实例。
- 割一块此山羊的肉交给生物学家,让他们克隆一只。—原型模式创建对象,只提供原型接口(肉)就可拷贝具体对象,不需要提供具体实例。

代码实现

// PrototypePattern.cpp : 定义控制台应用程序的入口点。
//

/******C++设计模式之原型模式********************/

#include <iostream>
#include <string>

using namespace std;

//Prototype
class Animal
{
public:
    Animal(){}
    virtual ~Animal(){}
    virtual Animal* clone() = 0;
    void show()
    {
        cout << "我是名为" << m_Name << "的山羊,年龄为" << m_Age << "岁" << endl;
    }
protected:
    int m_Age = 2;
    string m_Name;
};

//ConcretePrototype
class Sheep : public Animal
{
public:
    Sheep(string &name){ m_Name = name; }
    ~Sheep(){}
    Sheep(const Sheep& other);
    Animal* clone();
};

Sheep::Sheep(const Sheep& other)//拷贝构造
{
    this->m_Age = other.m_Age;
    this->m_Name = other.m_Name;
}

Animal* Sheep::clone()//利用拷贝构造克隆
{
    return new Sheep(*this);
}

//Client
int main()
{
    Animal *animal = new Sheep(string("狗蛋"));
    animal->show();

    Animal *CloneAnimal = animal->clone();//克隆山羊
    CloneAnimal -> show();

    return 0;
}

结果:
我是名为狗蛋的山羊,年龄为2岁
我是名为狗蛋的山羊,年龄为2岁
请键继续 .


4. 注意事项

说到拷贝构造函数就绕不开浅拷贝和深拷贝,二者区别在于是否重新开辟存储空间来存储依靠new创建的成员对象。 具体区别可自行百度。

5.总结

  • 优点:
    如果创建新的对象比较复杂,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
    简化对象的创建,无需理会创建过程。
    可以在程序运行时(对象属性发生了变化)获得一份内容相同的实例,他们之间不会相互干扰。
    • 缺点:
      在实现深拷贝时可能需要比较复杂的代码
      需要为每一个类配备一个克隆方法,而且该克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
    • 适用场景
      如果创建新对象成本较大,可以利用已有的对象进行复制来获得。
      如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。相反,如果对象的状态变化很大,或者对象占用的内存很大,那么采用状态模式会比原型模式更好。

猜你喜欢

转载自blog.csdn.net/a369189453/article/details/80787276