原型模式(Prototype Pattern): 创建重复的对象,同时又能保证性能,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
原型模型
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象
分析实现:
通过对象的拷贝,构造相同类型的对象。例如:试卷的复印
给类提供一个接口,实现对象的复制,这里注意类内成员的深拷贝和浅拷贝。
使用场景:
1:对象类型一开始不确定,运行中确定,可以克隆创建
2:需要使用对象的副本
3:创建对象时,过多的构造和析构,可以用原型模式
源码demo:
#include <iostream> #include <string.h> using namespace std; class Person {//抽象类提供接口 public: virtual Person *Clone() const = 0;//返回基类指针 virtual void printT() const = 0; virtual ~Person() {} }; class JavaProgrammer : public Person { private: string m_name; int m_age; char *m_resume; public: JavaProgrammer()//无参构造函数 { this->m_name = ""; this->m_age = 0; m_resume = NULL; } JavaProgrammer(string name, int age)//有参构造函数 { this->m_name = name; this->m_age = age; m_resume = NULL; } ~JavaProgrammer() { if (m_resume != NULL) { free(m_resume); m_resume = NULL; } } //实现自我复制功能 这里应该调用拷贝构造函数 但是涉及深拷贝与浅拷贝问题,这里直接做内存的处理 Person *Clone() const override { JavaProgrammer *p = new JavaProgrammer(); p->m_resume = new char[strlen(this->m_resume) + 1]; p->m_name = this->m_name; strcpy(p->m_resume, this->m_resume); // return new JavaProgrammer(*this); 浅拷贝 这里成员在析构中释放,会报错 return p; } void setResume(const char *resume) { m_resume = new char[strlen(resume) + 1]; //因为是字符串末尾多一个'\0' strcpy(m_resume, resume); } void printT() const override { cout << "m_name:" << m_name << "\t" << "m_age:" << m_age << endl; if (m_resume != NULL) { cout << m_resume << endl; } } }; int main() { JavaProgrammer javaperson1("李四", 160); javaperson1.setResume("我是C++程序员");//字符串操作,使用函数完成初始化操作。注意字符串操作的时候要进行'\0'' //如果不使用这个函数进行封装,那么就会出现深拷贝和浅拷贝的问题 //如果没有这个函数,那么在指针自我拷贝的时候吗,我们就要把内存给创建出来,然后在去进行赋值操作 javaperson1.printT();//自己打印自己的信息 Person *p2 = javaperson1.Clone(); //对象具有自我复制功能 注意深拷贝和浅拷贝问题 p2->printT(); if(p2 != NULL) { delete p2; p2 = NULL; } return 0; }
百度到一个好的代码: https://refactoringguru.cn/design-patterns/cpp
// 代码来自 https://refactoringguru.cn/design-patterns/cpp #include <iostream> #include <string.h> #include <map> #include <unordered_map> using std::string; enum Type { PROTOTYPE_1 = 0, PROTOTYPE_2 }; //定义原型模式的基础类 class Prototype { protected: string prototype_name_; float prototype_field_; public: Prototype() {} Prototype(string prototype_name): prototype_name_(prototype_name) {} virtual ~Prototype() {} virtual Prototype *Clone() const = 0; virtual void Method(float prototype_field) { this->prototype_field_ = prototype_field; std::cout << "Call Method from " << prototype_name_ << " with field : " << prototype_field << std::endl; } }; //子类实现不同的原型构造 浅拷贝拷贝构造 需要客户自己释放 class ConcretePrototype1 : public Prototype { private: float concrete_prototype_field1_; public: ConcretePrototype1(string prototype_name, float concrete_prototype_field) : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field) {} Prototype *Clone() const override { return new ConcretePrototype1(*this); } }; class ConcretePrototype2 : public Prototype { private: float concrete_prototype_field2_; public: ConcretePrototype2(string prototype_name, float concrete_prototype_field) : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field) { } Prototype *Clone() const override { return new ConcretePrototype2(*this); } }; //工厂方法对不同的原型进行管理 通过类型的传入进行拷贝构造 class PrototypeFactory { private: std::unordered_map<Type, Prototype *, std::hash<int>> prototypes_; public: PrototypeFactory() { prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f); prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f); } ~PrototypeFactory() { delete prototypes_[Type::PROTOTYPE_1]; delete prototypes_[Type::PROTOTYPE_2]; } Prototype *CreatePrototype(Type type) { return prototypes_[type]->Clone(); } }; //创建工厂类 通过传入参数控制原型类的拷贝构造 注意自己释放对应的内存 void Client(PrototypeFactory &prototype_factory) { std::cout << "Let's create a Prototype 1\n"; Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1); prototype->Method(90); delete prototype; std::cout << "\n"; std::cout << "Let's create a Prototype 2 \n"; prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2); prototype->Method(10); delete prototype; } int main() { PrototypeFactory *prototype_factory = new PrototypeFactory(); Client(*prototype_factory); delete prototype_factory; return 0; }