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

一,原型模式的定义

原型模式是一种创建型设计模式,它允许通过克隆已有对象来创建新对象,从而无需调用显式的实例化过程。

原型模式的设计,使得它可以创建一个与原型对象相同或类似的新对象,同时又可以减少对象实例化操作产生的性能开销,使得创建对象的操作更加便捷,它减少了大量不必要的重复工作,并提高了系统性能。

当创建对象的操作比较复杂和耗时的时候,原型模式则提供了一个更加高效和简单的创建对象的模式,它可以更加快速的创建对象的副本,且不需要依赖对象的某些实例化步骤,它避免了使用传统的new关键字创建对象实例时的复杂构造过程。

原型模式的主要缺点则是原型对象必须预先存在于系统中,并且需要预先进行注册。此时,如果有大量的原型对象需要被创建,并且每个原型对象都需要进行自定义,维护和管理这些原型对象可能会变得很复杂。

原型模式在现实生活中的抽象实例:

图形绘制:假设我们需要绘制不同形状的图形,可以定义一个图形类作为原型,然后通过克隆该原型对象来创建具体的图形对象。

陶艺制作:先制作一个陶艺原型作为参考,然后通过复制或克隆原型来制作出多个相似的陶艺品。

服装设计:设计师预先设计一套成衣样板,然后通过复制或克隆样板来制作出多件相似或不同款式的服装。

二,原型模式的结构

原型模式主要包含以下组件:

1.抽象原型(Prototype):定义克隆方法的接口,具体原型类通过实现这些方法来提供其自身的副本。

2.具体原型(ConcretePrototype):包含抽象原型类的具体实现,它会提供一个复制自身的方法,该方法将创建并返回一个对象副本。

3.客户端(Client):客户端使用原型类来创建新对象的副本,它会先获取原型对象,并使用原型对象的克隆方法来创建新的对象实例。

组件之间的工作步骤如下:

1.客户端通过实例化具体原型类,并调用其克隆方法来创建一个原型对象。

2.原型对象调用自身的克隆方法,将自身复制一份,返回一个克隆的对象。

3.客户端获取到克隆对象后,可以根据自身的业务需求对其进行进一步的修改和使用。

对应UML类图:

三,原型模式代码样例

Demo1:

#include <iostream>
#include <string>

//定义原型基类
class Prototype {
public:
    virtual ~Prototype() {}
    virtual Prototype* clone() const = 0;
    virtual void print() const = 0;
};

//定义具体原型类
class ConcretePrototype : public Prototype{
private:
    std::string name;
public:
    ConcretePrototype(const std::string& name) : name(name) {}
    Prototype* clone() const override {
        return new ConcretePrototype(*this);
    }
    void print() const override {
        std::cout << "Prototype: " << name << std::endl;
    }
};

int main() {
    //创建原型对象
    ConcretePrototype prototype("Original");
    //使用原型对象创建新对象
    Prototype* clone = prototype.clone();
    clone->print();
    //释放内存
    delete clone;
    return 0;
}

运行结果:

Prototype: Original

Demo2:

#include <iostream>
#include <string>

class Prototype {
public:
    virtual ~Prototype() {}
    virtual Prototype* clone() const = 0;
    virtual void info() const = 0;
};

class ConcretePrototypeA: public Prototype {
public:
    ConcretePrototypeA(int id, std::string name)
        : m_id(id), m_name(name) {}
    Prototype* clone() const override {
        return new ConcretePrototypeA(*this);
    }
    void info() const override {
        std::cout << "ConcretePrototypeA: id = "
                  << m_id << ", name = " 
                  << m_name <<  std::endl;
    }
private:
    int m_id;
    std::string m_name;
};

class ConcretePrototypeB: public Prototype {
public:
    ConcretePrototypeB(std::string description)
        : m_description(description) {}
    Prototype* clone() const override {
        return new ConcretePrototypeB(*this);
    }
    void info() const override {
        std::cout << "ConcretePrototypeB: description = " 
                  << m_description <<  std::endl;
    }
private:
    std::string m_description;
};

int main() {
    ConcretePrototypeA* prototypeA = new ConcretePrototypeA(1, "First");
    Prototype* cloneA = prototypeA->clone();
    cloneA->info();
    ConcretePrototypeB* prototypeB = new ConcretePrototypeB("This is a prototype");
    Prototype* cloneB = prototypeB->clone();
    cloneB->info();
    delete prototypeA;
    delete cloneA;
    delete prototypeB;
    delete cloneB;
    return 0;
}

运行结果:

ConcretePrototypeA: id = 1, name = First
ConcretePrototypeB: description = This is a prototype

四,原型模式的应用场景

图形用户界面:创建可定制的控件,如Windows的对话框,设计一个原型控件,让用户根据需求选择属性进行定制。

文本编辑器开发:支持“剪切”、“复制”、“粘贴”的功能,使用已存在的文档作为复制和创建新文档的原型。

数据库开发:将数据库的某个状态视为原型,当需要创建新的数据库版本时,可以直接从这个原型复制。

配置工具开发:基于原型模式帮助快速生成配置对象,而无需每次都新建一个空的配置。

Web应用程序:让用户可以在原型基础上添加、修改字段,动态生成表单元素。

五,原型模式的优缺点

原型模式的优点:

简化了对象的创建过程,使得代码更加简洁且易于维护。

提高了动态创建对象和销毁对象的效率。

封装和隐藏了创建对象的细节。

减少了对构造函数的直接调用,提高了代码的性能。

支持灵活的定制具体对象的属性和方法。

原型模式的缺点:

需要实现克隆对象的接口。

需要配合深拷贝或浅拷贝来使用,可能会导致引用对象的复制。

有的原型模式基于递归的方式来克隆对象,可能会引起堆栈溢出的问题。

针对大型对象的复制,会占用特别多的内存。

六,代码实战

Demo1:基于智能指针封装的原型模式:

#include <memory>
#include <iostream>

class Prototype {
public:
    virtual std::unique_ptr<Prototype> clone() const = 0;
    void printValue() const {
        std::cout << "Origin Value." << std::endl;
    }
};

class ConcretePrototype : public Prototype {
private:
    int value;
public:
    ConcretePrototype(int v) : value(v) {}
    std::unique_ptr<Prototype> clone() const override {
        return std::make_unique<ConcretePrototype>(value);
    }
    void printValue() const {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    auto prototype = std::make_unique<ConcretePrototype>(5);
    auto clonedPrototype = prototype->clone();
    prototype->printValue();
    clonedPrototype->printValue();
    return 0;
}

运行结果:

Value: 5
Origin Value.

Demo2:基于工厂的方式管理各种原型

#include <iostream>
#include <string>
#include <map>

class Prototype {
public:
    int data;
    std::string name;
    Prototype(int data, const std::string& name) : data(data), name(name) {}
    virtual Prototype* clone() {
        return new Prototype(*this);
    }
};

class PrototypeFactory {
private:
    std::map<std::string, Prototype*> prototypes;
public:
    PrototypeFactory() {
        prototypes["original"] = new Prototype(40, "Original");
        prototypes["copy"] = new Prototype(100, "Copy");
    }
    Prototype* create(const std::string& type) {
        return prototypes[type]->clone();
    }
};

int main() {
    PrototypeFactory factory;
    Prototype* original = factory.create("original");
    Prototype* copy = factory.create("copy");

    std::cout << "Original: data="
              << original->data
              << ", name="
              << original->name << std::endl;
    std::cout << "Copy: data="
              << copy->data
              << ", name="
              << copy->name << std::endl;

    delete original;
    delete copy;
    return 0;
}

运行结果:

Original: data=40, name=Original
Copy: data=100, name=Copy

七,参考阅读

https://softwarepatterns.com/cpp/prototype-software-pattern-cpp-example

https://www.geeksforgeeks.org/prototype-design-pattern/

https://www.tutorialspoint.com/design_pattern/prototype_pattern.html

https://sourcemaking.com/design_patterns/prototype

https://softwareparticles.com/design-patterns-prototype/

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值