设计模式 — 原型模式
原型模式是一种创建型设计模式,它允许你在不指定具体类的情况下创建新的对象。通过克隆一个现有的对象来创建新的对象,而不是通过常规的构造函数。这样可以简化对象的创建过程,尤其是在对象的创建过程比较复杂时。
在c++中,实现原型模式一般可以有两种方式实现,第一种方法是编写正确的拷贝原始对象的代码,比如,拷贝工作可以在拷贝构造、赋值运算符或者在单独的类成员函数中实现,第二种方法是编写序列化/反序列化的代码,比如利用boost.serialization的库在完成序列化后立即进行反序列化,由此完成复制拷贝工作。
以下,我们将使用类成员方法的方式分别演示“拷贝原始对象”&“序列化/反序列化”这两种主要途径实现原型模式。
1. 编写拷贝原始对象的方式
1.1 定义原型接口
#include <iostream>
#include <memory>
class Prototype {
public:
virtual ~Prototype() = default;
virtual std::shared_ptr<Prototype> clone() const = 0;
};
1.2 定义具体原型类
class ConcretePrototype1 : public Prototype {
public:
ConcretePrototype1(int value) : value(value) {}
std::shared_ptr<Prototype> clone() const override {
// 使用拷贝构造函数克隆对象
// 具体类的成员可在其构造中初始化,也可在clone方法中初始化或者赋值
return std::make_shared<ConcretePrototype1>(*this);
}
void printValue() const {
std::cout << "ConcretePrototype1 value: " << value << std::endl;
}
private:
int value;
};
class ConcretePrototype2 : public Prototype {
public:
ConcretePrototype2(double value) : value(value) {}
std::shared_ptr<Prototype> clone() const override {
// 使用拷贝构造函数克隆对象
// 具体类的成员可在其构造中初始化,也可在clone方法中初始化或者赋值
return std::make_shared<ConcretePrototype2>(*this);
}
void printValue() const {
std::cout << "ConcretePrototype2 value: " << value << std::endl;
}
private:
double value;
};
1.3 客户端(调用方)
int main() {
// 创建具体原型对象
// 创建时可传入自定义列表初始化类成员
auto prototype1 = std::make_shared<ConcretePrototype1>(10);
auto prototype2 = std::make_shared<ConcretePrototype2>(20.5);
// 克隆原型对象
auto clonedPrototype1 = prototype1->clone();
auto clonedPrototype2 = prototype2->clone();
// 打印克隆对象的值
clonedPrototype1->printValue();
clonedPrototype2->printValue();
return 0;
}
2. 使用序列化/反序列化
2.1 定义原型接口
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <boost/serialization/access.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class Prototype {
public:
virtual ~Prototype() = default;
virtual std::shared_ptr<Prototype> clone() const = 0;
};
2.2 定义具体原型类
class ConcretePrototype1 : public Prototype {
public:
ConcretePrototype1(int value) : value(value) {}
std::shared_ptr<Prototype> clone() const override {
// 使用序列化/反序列化克隆对象
std::ostringstream archiveStream;
boost::archive::text_oarchive outputArchive(archiveStream);
outputArchive << *this;
std::istringstream archiveStreamCopy(archiveStream.str());
boost::archive::text_iarchive inputArchive(archiveStreamCopy);
std::shared_ptr<ConcretePrototype1> clonedObject(new ConcretePrototype1());
inputArchive >> *clonedObject;
return std::shared_ptr<Prototype>(clonedObject);
}
void printValue() const {
std::cout << "ConcretePrototype1 value: " << value << std::endl;
}
private:
friend class boost::serialization::access;
/*
* serialize 是一个模板方法,用于定义如何将对象的成员变量序列化和反序列化,
* 虽然没有显示调用,但是,boost::serialization 库会自动调用这个方法来
* 处理对象的序列化和反序列化过程。当你使用 outputArchive << *this; 和
* inputArchive >> *clonedObject; 时,boost::serialization 会自动
* 调用 serialize 方法来处理对象的序列化和反序列化。
*/
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & value;
}
int value;
};
class ConcretePrototype2 : public Prototype {
public:
ConcretePrototype2(double value) : value(value) {}
std::shared_ptr<Prototype> clone() const override {
// 使用序列化/反序列化克隆对象
std::ostringstream archiveStream;
boost::archive::text_oarchive outputArchive(archiveStream);
outputArchive << *this;
std::istringstream archiveStreamCopy(archiveStream.str());
boost::archive::text_iarchive inputArchive(archiveStreamCopy);
std::shared_ptr<ConcretePrototype2> clonedObject(new ConcretePrototype2());
inputArchive >> *clonedObject;
return std::shared_ptr<Prototype>(clonedObject);
}
void printValue() const {
std::cout << "ConcretePrototype2 value: " << value << std::endl;
}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & value;
}
double value;
};
2.3 客户端代码
客户端调用代码示例同“1.3”中所示,此处略!
总之:原型模式通过克隆一个现有的对象来创建新的对象,适用于对象创建过程复杂或需要创建多个相似对象的场景。在 C++ 中,可以通过编写拷贝构造函数和赋值操作符来实现克隆,也可以通过序列化/反序列化来实现克隆。每种方法都有其优缺点,选择哪种方法取决于具体的应用场景和需求。