
C++ 原型模式讲解和代码示例
原型是一种创建型设计模式, 使你能够复制对象, 甚至是复杂对象, 而又无需使代码依赖它们所属的类。
所有的原型类都必须有一个通用的接口, 使得即使在对象所属的具体类未知的情况下也能复制对象。 原型对象可以生成自身的完整副本, 因为相同类的对象可以相互访问对方的私有成员变量。
复杂度:
流行度:
识别方法: 原型可以简单地通过 clone
或 copy
等方法来识别。
概念示例
本例说明了原型设计模式的结构并重点回答了下面的问题:
- 它由哪些类组成?
- 这些类扮演了哪些角色?
- 模式中的各个元素会以何种方式相互关联?
main.cc: 概念示例
using std::string;
// Prototype Design Pattern
//
// Intent: Lets you copy existing objects without making your code dependent on
// their classes.
enum Type {
PROTOTYPE_1 = 0,
PROTOTYPE_2
};
/**
* The example class that has cloning ability. We'll see how the values of field
* with different types will be cloned.
*/
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;
}
};
/**
* ConcretePrototype1 is a Sub-Class of Prototype and implement the Clone Method
* In this example all data members of Prototype Class are in the Stack. If you
* have pointers in your properties for ex: String* name_ ,you will need to
* implement the Copy-Constructor to make sure you have a deep copy from the
* clone method
*/
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) {
}
/**
* Notice that Clone method return a Pointer to a new ConcretePrototype1
* replica. so, the client (who call the clone method) has the responsability
* to free that memory. If you have smart pointer knowledge you may prefer to
* use unique_pointer here.
*/
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);
}
};
/**
* In PrototypeFactory you have two concrete prototypes, one for each concrete
* prototype class, so each time you want to create a bullet , you can use the
* existing ones and clone those.
*/
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);
}
/**
* Be carefull of free all memory allocated. Again, if you have smart pointers
* knowelege will be better to use it here.
*/
~PrototypeFactory() {
delete prototypes_[Type::PROTOTYPE_1];
delete prototypes_[Type::PROTOTYPE_2];
}
/**
* Notice here that you just need to specify the type of the prototype you
* want and the method will create from the object with this type.
*/
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;
}
Output.txt: 执行结果
Let's create a Prototype 1
Call Method from PROTOTYPE_1 with field : 90
Let's create a Prototype 2
Call Method from PROTOTYPE_2 with field : 10