抽象不能依赖于实现细节,实现细节应该依赖于抽象。
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作,由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。Prototype设计模式,就是为了解决如何向“客户程序”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求的改变而改变。
Prototype设计模式指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
要点:
- Prototype设计模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。
- Prototype设计模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象,所需要的工作仅仅是注册一个新类的对象(即原型),然后在需要的地方不断地Clone
- Clone时要注意使用Deep Clone。
- 在Java中可以考虑使用序列化或者直接new一个新的子对象的方式来实现Deep Clone;
- 在C++中一般采用直接new一个新的子对象的方法来实现Deep Clone;
- 在C#中一般采用MemberwiseClone()方法、序列化方法或者直接用new一个新的子对象的方法来实现Deep Clone。
Prototype模式最主要的两个值得注意的地方:
1. 以Clone的方式创建对象
2. 一个对象需要多个副本以进行不同的处理。For example, let’s consider the case in which you need to make a number of queries to an extensive database to construct an answer. Once you have this answer as a table or ResultSet, you might want to manipulate it to produce other answers without your having to issue additional queries. (下面的实现代码,即以此为例)
Prototype模式之UML类图:
C++实现Prototype模式的具体示例代码:
// Prototype.h
#include <iostream>
#include <vector>
#include <memory>
#include <string>
using namespace std;
// 跳水运动员,模拟数据库的一条记录
class Diver
{
private:
int id; // 跳水运动员的id
string name; // 跳水运动员的姓名
double score; // 跳水运动员的分数
public:
void set_id(const int& id)
{
this->id = id;
}
int get_id() const
{
return id;
}
void set_name(const string& name)
{
this->name = name;
}
string get_name() const
{
return name;
}
void set_score(const double& score)
{
this->score = score;
}
double get_score() const
{
return score;
}
public:
~Diver()
{
cout << "in destructor of Diver..." << endl;
}
};
// 抽象类,模拟从数据库读取的一个结果集,相当于UML类图中的Prototype类
class ResultSet
{
protected:
vector<Diver> divers;
public:
virtual auto_ptr<ResultSet> clone() = 0;
virtual vector<Diver> get_divers() = 0;
virtual bool sort(const string& by_what_rule) = 0;
virtual ~ResultSet()
{
cout << "in the destructor of ResultSet..." << endl;
}
};
// 相当于UML类图中的ConcreatePrototype1类
class DiversResultSet : public ResultSet
{
public:
DiversResultSet() // 模拟一个结果集
{
Diver d1, d2, d3;
d1.set_id(1);
d1.set_name("Jack Jones");
d1.set_score(634.28);
divers.push_back(d1);
d2.set_id(2);
d2.set_name("Nick Xiong");
d2.set_score(686.98);
divers.push_back(d2);
d3.set_id(3);
d3.set_name("Frank Bryant");
d3.set_score(636.68);
divers.push_back(d3);
}
vector<Diver> get_divers()
{
return divers;
}
auto_ptr<ResultSet> clone() // 这个函数整个Prototype模式中的关键
{
auto_ptr<ResultSet> divers_result_set(new DiversResultSet());
return divers_result_set;
}
bool sort(const string& by_what_rule)
{
if((by_what_rule.compare("score") != 0) && (by_what_rule.compare("name") != 0))
{
return false;
}
else if(by_what_rule.compare("score") == 0) // 下面代码模拟按照分数排序
{
Diver d1 = divers[0];
Diver d2 = divers[1];
Diver d3 = divers[2];
divers.resize(0);
divers.push_back(d2);
divers.push_back(d3);
divers.push_back(d1);
}
else // 下面代码模拟按照姓名排序
{
Diver d1 = divers[0];
Diver d2 = divers[1];
Diver d3 = divers[2];
divers.resize(0);
divers.push_back(d3);
divers.push_back(d1);
divers.push_back(d2);
}
return true;
}
public:
~DiversResultSet()
{
cout << "in the destructor of DiversResultSet..." << endl;
}
};
// 测试代码:
// Prototype.cpp
#include "Prototype.h"
int main(int agrc, char **argv)
{
auto_ptr<ResultSet> rs(new DiversResultSet);
vector<Diver> vd1 = rs->get_divers();
auto_ptr<ResultSet> rs1(rs->clone()); // 克隆一次
auto_ptr<ResultSet> rs2(rs->clone()); // 再克隆一次
for(vector<Diver>::const_iterator cit = vd1.begin(); cit != vd1.end(); cit++)
{
cout << cit->get_id() << " " << cit->get_name() << "\t\t" << cit->get_score() << endl;
}
rs1->sort("score");
vector<Diver> vd2 = rs1->get_divers();
for(vector<Diver>::const_iterator cit = vd2.begin(); cit != vd2.end(); cit++)
{
cout << cit->get_id() << " " << cit->get_name() << "\t\t" << cit->get_score() << endl;
}
rs2->sort("name");
vector<Diver> vd3 = rs2->get_divers();
for(vector<Diver>::const_iterator cit = vd3.begin(); cit != vd3.end(); cit++)
{
cout << cit->get_id() << " " << cit->get_name() << "\t\t" << cit->get_score() << endl;
}
}
上述程序的输出结果大致如下:
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
1 Jack Jones 634.28
2 Nick Xiong 686.98
3 Frank Bryant 636.68
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
2 Nick Xiong 686.98
3 Frank Bryant 636.68
1 Jack Jones 634.28
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
3 Frank Bryant 636.68
1 Jack Jones 634.28
2 Nick Xiong 686.98
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in the destructor of DiversResultSet...
in the destructor of ResultSet...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in the destructor of DiversResultSet...
in the destructor of ResultSet...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...
in the destructor of DiversResultSet...
in the destructor of ResultSet...
in destructor of Diver...
in destructor of Diver...
in destructor of Diver...