原型模式

原型模式是一种创建型设计模式,使用它可以复制已有对象,并且不需要依赖已有对象所属的类。

如果需要复制一个对象,该怎么做呢?
称想要复制的对象为对象A,复制得到的对象为对象B。分为两步:

  1. 用A的类新建一个实例对象,这个对象就是B
  2. 把A的所有属性值都赋值给B。复制结束。

这两步每一步都有问题,第一步当前代码必须能够访问A所属的类,有一种场景,方法的参数是接口类型,一个类只要实现了接口,其对象就可以作为参数传递。这时方法里的代码无法访问参数的实际类型。
第二步,A所属的类有些属性是私有的。从外部无法访问。

解决办法:原型模式

原型模式将上门的两步从A类外转移到A类内,那么上面两步的问题就不存在了。声明一个包含克隆方法的通用接口interface,让A的类实现这个接口。当需要A的克隆对象时,只需要A调用克隆方法即可。

类图:

2024-01-10T09:20:35.png

代码示例:

#include <iostream>
#include <string>

// 1. 原型接口
class Prototype {
public:
    virtual Prototype* clone() const = 0;
    virtual void display() const = 0;
};

// 2. 具体原型
class ConcretePrototype : public Prototype {
public:
    ConcretePrototype(int field1)
        : field1_(field1) {}

    // 实现深拷贝
    Prototype* clone() const override {
        return new ConcretePrototype(*this);
    }

    void display() const override {
        std::cout << "ConcretePrototype: Field1 = " << field1_ << std::endl;
    }

    int getField1() const {
        return field1_;
    }

private:
    int field1_;
};

// 3. 具体原型的子类
class SubConcretePrototype : public ConcretePrototype {
public:
    SubConcretePrototype(int field1, std::string field2)
        : ConcretePrototype(field1), field2_(std::move(field2)) {}

    // 实现深拷贝
    Prototype* clone() const override {
        return new SubConcretePrototype(*this);
    }

    void display() const override {
        std::cout << "SubConcretePrototype: Field1 = " << getField1() << ", Field2 = " << field2_ << std::endl;
    }

    std::string getField2() const {
        return field2_;
    }

private:
    std::string field2_;
};

int main() {
    // 使用原型模式创建新对象
    ConcretePrototype prototype(42);
    prototype.display();

    // 克隆原型对象
    Prototype* clonedPrototype = prototype.clone();
    clonedPrototype->display();

    // 使用具体原型的子类创建新对象
    SubConcretePrototype subPrototype(1, "Hello");
    subPrototype.display();

    // 克隆具体原型的子类对象
    Prototype* clonedSubPrototype = subPrototype.clone();
    clonedSubPrototype->display();

    // 释放资源
    delete clonedPrototype;
    delete clonedSubPrototype;

    return 0;
}