Prototype

原型

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
当创建给定类的实例的过程很昂贵很复杂时,就使用原型模式。通过复制现有的实例来创建新的实例。

适用性

  • 当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式;
  • 当要实例化的类是在运行时刻指定时,例如,通过动态加载;或者
  • 为了避免创建一个与产品类层次平行的工厂类层次时;或者
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

结构

Prototype UML

Prototype - 声明一个克隆自身的接口。
ConcretePrototype - 实现一个克隆自身的操作。
Client - 让一个原型克隆自身从而创建一个新的对象。

协作:
客户请求一个原型克隆自身。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <iostream>
#include <string>
//---------------------------------------------------
class Prototype
{
public:
virtual void display() = 0;
virtual Prototype* clone() = 0;
};
//---------------------------------------------------
class ConcretePrototype1 : public Prototype
{
public:
ConcretePrototype1():Prototype(), m_param("param1"){}
ConcretePrototype1(const ConcretePrototype1& other) : Prototype(other)
{
m_param = other.m_param;
}
virtual void display()
{

std::cout<<"I'm ConcretePrototype1, Parameter: "<<m_param<<std::endl;
}
virtual Prototype* clone()
{

return new ConcretePrototype1(*this);
}
private:
std::string m_param;
};
//---------------------------------------------------
class ConcretePrototype2 : public Prototype
{
public:
ConcretePrototype2():Prototype(), m_param("param2"){}
ConcretePrototype2(const ConcretePrototype2& other) : Prototype(other)
{
m_param = other.m_param;
}
virtual void display()
{

std::cout<<"I'm ConcretePrototype2, Parameter: "<<m_param<<std::endl;
}
virtual Prototype* clone()
{

return new ConcretePrototype2(*this);
}
private:
std::string m_param;
};
//---------------------------------------------------
class Other
{
public:
Other() : m_temp(0){}
int m_temp;
};
//---------------------------------------------------
class Product
{
public:
Prototype* m_prototype1;
Prototype* m_prototype2;
Other* m_other;
void display()
{

if (!m_other || !m_prototype1 || !m_prototype2) return;
std::cout<<"Product: "<<std::endl;
m_prototype1->display();
m_prototype2->display();
std::cout<<m_other->m_temp<<std::endl;
}
};
//---------------------------------------------------
class PrototypeFactory
{
public:
PrototypeFactory(Prototype* p, Other* o) : m_prototype(p), m_other(o){}
virtual Product* make_product() const
{

if (!m_prototype || !m_other) return NULL;
Product* p = new Product();
p->m_prototype1 = m_prototype->clone(); // 传入一个原型,每次使用时clone一个。
p->m_prototype2 = m_prototype->clone();
p->m_other = m_other;
return p;
}
private:
Prototype* m_prototype;
Other* m_other;
};
//---------------------------------------------------
class Client
{
public:
Product* create_product(PrototypeFactory& factory)
{

return factory.make_product();
}
};
//---------------------------------------------------
int main()
{

Client client;
PrototypeFactory factory1(new ConcretePrototype1, new Other); // 传入的这一个原型使用了两次
Product* p1 = client.create_product(factory1);
p1->display();

PrototypeFactory factory2(new ConcretePrototype2, new Other); // 传入的这一个原型使用了两次
Product* p2 = client.create_product(factory2);
p2->display();
system("Pause");
}

优点

  • 向客户隐藏创造新实例的复杂性。
  • 提供让客户能够产生未知类型对象的选项。
  • 在某些环境下,复制对象比创建新对象更有效。
  • 运行时刻增加和删除产品。
  • 改变值以指定新对象。
  • 改变结构以指定新对象。
  • 减少子类的构造。不像Factory Method一样需要Creator类层次。
  • 对C++这样的静态语言尤其有用。

用途和缺点

  • 在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型。
  • 使用原型模式的缺点:对象的复制有时相当复杂。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First 设计模式