设计模式 - 原型模式(Prototype Pattern)

设计模式 - 原型模式(Prototype Pattern)

flyfish

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类来创建。原型模式适用于需要生成大量相似对象的情况,尤其是当创建对象的代价较高或复杂时。

原型模式的关键概念

  • 原型接口 :定义一个方法用于克隆对象。

  • 具体原型类 :实现克隆方法,通常使用浅复制或深复制。

  • 客户端 :通过调用原型对象的克隆方法来创建新对象。

英文原文

Ordinarily, classes that manage resources that do not reside in the class must define the copy-control members. Such classes will need destructors to free the resources allocated by the object. Once a class needs a destructor, it almost surely needs a copy constructor and copy-assignment operator as well.

In order to define these members, we first have to decide what copying an object of our type will mean. In general, we have two choices: We can define the copy operations to make the class behave like a value or like a pointer.

Classes that behave like values have their own state. When we copy a value-like object, the copy and the original are independent of each other. Changes made to the copy have no effect on the original, and vice versa.

Classes that act like pointers share state. When we copy objects of such classes, the copy and the original use the same underlying data. Changes made to the copy also change the original, and vice versa.

解释

Copy-Control Members:
Destructor (析构函数): 用于释放对象占用的资源。
Copy Constructor (拷贝构造函数): 用于创建一个新对象作为现有对象的副本。
Copy Assignment Operator (拷贝赋值运算符): 用于将一个已存在的对象的状态赋给另一个对象。

Value Semantics (值语义):
当一个类的行为类似于内置类型(如 int 或 double)时,我们说它具有值语义。值语义意味着每个对象都有自己的状态,对象之间的复制会导致完全独立的对象。

Pointer Semantics (指针语义):
类似于指针的行为,即多个对象可能指向相同的资源。在这种情况下,对象间的复制不会导致资源的复制,而是导致多个对象共享同一份资源。

Deep Copy vs. Shallow Copy (深拷贝与浅拷贝):
Deep Copy (深拷贝): 创建一个新的独立的资源副本。这意味着原始对象和其副本各自拥有独立的数据。对副本所做的任何修改都不会影响到原始对象。
Shallow Copy (浅拷贝): 创建一个新的对象,但不复制所指向的数据,而是共享同一份数据。这意味着原始对象和其副本会引用相同的资源。对副本所做的任何修改都会影响到原始对象。

Independent Objects (独立对象):
指那些即使被复制也不会共享内部状态的对象。每个对象都有其独有的资源副本。

Shared State (共享状态):
指的是多个对象引用同一份资源的情况。在这种情况下,对象间的变化会影响到所有共享该资源的对象

中文:

通常,管理不在类内驻留的资源的类必须定义复制控制成员。这些类需要定义析构函数以释放对象分配的资源。一旦类需要析构函数,它几乎肯定也需要复制构造函数和复制赋值运算符。

为了定义这些成员,我们首先必须决定复制我们类型的对象意味着什么。一般来说,我们有两个选择:我们可以将复制操作定义为使类表现得像值或像指针。

表现得像值的类有其自己的状态。当我们复制一个值类型的对象时,副本和原始对象是彼此独立的。对副本所做的更改对原始对象没有影响,反之亦然。

表现得像指针的类共享状态,当我们复制这样的类的对象时,副本和原始对象使用相同的底层数据。对副本所做的更改也会更改原始对象,反之亦然。

简单的例子

  1. Prototype 接口 :定义了一个 Clone 方法,用于克隆对象。

  2. ConcretePrototype1 和 ConcretePrototype2 类 :实现了 Prototype 接口,并定义了 Clone 方法。

  3. PrototypeRegistry 类 :用于存储和管理原型,通过注册原型并通过键值克隆对象。

  4. 主函数 :创建原型注册表,注册具体原型,并通过克隆方法创建新对象。

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>

// 原型接口
class Prototype {
public:
    virtual ~Prototype() = default;
    // 克隆方法,用于复制当前对象
    virtual std::unique_ptr<Prototype> Clone() const = 0;
    virtual void Print() const = 0;
};

// 具体原型类1
class ConcretePrototype1 : public Prototype {
private:
    std::string name_;
public:
    ConcretePrototype1(const std::string& name) : name_(name) {}

    // 实现克隆方法,返回当前对象的浅复制
    std::unique_ptr<Prototype> Clone() const override {
        return std::make_unique<ConcretePrototype1>(*this);
    }

    void Print() const override {
        std::cout << "ConcretePrototype1 with name: " << name_ << std::endl;
    }
};

// 具体原型类2
class ConcretePrototype2 : public Prototype {
private:
    int value_;
public:
    ConcretePrototype2(int value) : value_(value) {}

    // 实现克隆方法,返回当前对象的浅复制
    std::unique_ptr<Prototype> Clone() const override {
        return std::make_unique<ConcretePrototype2>(*this);
    }

    void Print() const override {
        std::cout << "ConcretePrototype2 with value: " << value_ << std::endl;
    }
};

// 原型注册表,用于存储和克隆原型
class PrototypeRegistry {
private:
    std::unordered_map<std::string, std::unique_ptr<Prototype>> prototypes_;
public:
    void RegisterPrototype(const std::string& key, std::unique_ptr<Prototype> prototype) {
        prototypes_[key] = std::move(prototype);
    }

    std::unique_ptr<Prototype> CreatePrototype(const std::string& key) const {
        if (prototypes_.find(key) != prototypes_.end()) {
            return prototypes_.at(key)->Clone();
        }
        return nullptr;
    }
};

int main() {
    // 创建原型注册表
    PrototypeRegistry registry;

    // 注册两个具体原型
    registry.RegisterPrototype("Type1", std::make_unique<ConcretePrototype1>("Prototype1"));
    registry.RegisterPrototype("Type2", std::make_unique<ConcretePrototype2>(42));

    // 使用原型创建对象
    std::unique_ptr<Prototype> prototype1 = registry.CreatePrototype("Type1");
    std::unique_ptr<Prototype> prototype2 = registry.CreatePrototype("Type2");

    // 打印对象信息
    if (prototype1) {
        prototype1->Print();
    }
    if (prototype2) {
        prototype2->Print();
    }

    return 0;
}

示例代码2

  1. Shape 类 :定义了基础原型,包含坐标和颜色字段,以及一个纯虚函数 Clone 用于克隆对象。

  2. Rectangle 类Circle 类 :具体原型类,继承自 Shape,并实现了 Clone 方法。每个类都有其特定的字段。

  3. Application 类 :模拟客户端应用,创建并存储形状对象,通过调用克隆方法来生成对象副本。

  4. BusinessLogic 方法 :演示如何在不知晓对象具体类型的情况下生成对象副本,并打印出每个对象的信息。
    一个抽象基类 Shape 和两个具体原型类 RectangleCircle,以及客户端代码中的应用示例。代码包括详细的中文注释以帮助理解。

#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 基础原型类
class Shape {
public:
    int X;  // X 坐标
    int Y;  // Y 坐标
    std::string color;  // 颜色

    // 常规构造函数
    Shape() : X(0), Y(0), color("undefined") {}

    // 原型构造函数,用于使用已有对象的数值来初始化新对象
    Shape(const Shape& source) : X(source.X), Y(source.Y), color(source.color) {}

    // 克隆方法,返回一个新的 Shape 对象
    virtual std::unique_ptr<Shape> Clone() const = 0;

    // 打印对象信息
    virtual void Print() const {
        std::cout << "Shape: (" << X << ", " << Y << "), color: " << color << std::endl;
    }

    virtual ~Shape() = default; // 虚析构函数,确保子类析构函数被正确调用
};

// 具体原型类:Rectangle
class Rectangle : public Shape {
public:
    int width;  // 宽度
    int height; // 高度

    // 构造函数
    Rectangle() : width(0), height(0) {}

    // 原型构造函数
    Rectangle(const Rectangle& source) : Shape(source), width(source.width), height(source.height) {}

    // 实现克隆方法
    std::unique_ptr<Shape> Clone() const override {
        return std::make_unique<Rectangle>(*this);
    }

    // 打印对象信息
    void Print() const override {
        std::cout << "Rectangle: (" << X << ", " << Y << "), color: " << color 
                  << ", width: " << width << ", height: " << height << std::endl;
    }
};

// 具体原型类:Circle
class Circle : public Shape {
public:
    int radius; // 半径

    // 构造函数
    Circle() : radius(0) {}

    // 原型构造函数
    Circle(const Circle& source) : Shape(source), radius(source.radius) {}

    // 实现克隆方法
    std::unique_ptr<Shape> Clone() const override {
        return std::make_unique<Circle>(*this);
    }

    // 打印对象信息
    void Print() const override {
        std::cout << "Circle: (" << X << ", " << Y << "), color: " << color 
                  << ", radius: " << radius << std::endl;
    }
};

// 客户端代码
class Application {
public:
    std::vector<std::unique_ptr<Shape>> shapes; // 存储形状的数组

    Application() {
        // 创建一个圆形并添加到 shapes 数组
        auto circle = std::make_unique<Circle>();
        circle->X = 10;
        circle->Y = 10;
        circle->radius = 20;
        circle->color = "Red";
        shapes.push_back(circle->Clone()); // 克隆并添加到 shapes

        // 克隆 `circle` 对象,创建 `anotherCircle`
        auto anotherCircle = circle->Clone();
        shapes.push_back(std::move(anotherCircle));

        // 创建一个矩形并添加到 shapes 数组
        auto rectangle = std::make_unique<Rectangle>();
        rectangle->X = 5;
        rectangle->Y = 5;
        rectangle->width = 10;
        rectangle->height = 20;
        rectangle->color = "Blue";
        shapes.push_back(rectangle->Clone()); // 克隆并添加到 shapes
    }

    void BusinessLogic() {
        // 原型非常强大,可以在不知晓对象类型的情况下生成其复制品
        std::vector<std::unique_ptr<Shape>> shapesCopy;

        // 遍历 shapes 数组,克隆每个元素并添加到 shapesCopy
        for (const auto& shape : shapes) {
            shapesCopy.push_back(shape->Clone());
        }

        // 打印 shapesCopy 中每个形状的信息
        for (const auto& shape : shapesCopy) {
            shape->Print();
        }
    }
};

int main() {
    Application app;  // 创建应用实例
    app.BusinessLogic();  // 执行业务逻辑

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西笑生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值