原型模式

理论

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

 原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。

实例

要求有一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历。最终需要写三份简历。

初步实现

#include <iostream>
using namespace std;

//简历类
class Resume {
private:
	string name;
	string sex;
	int age;
	string timeArea;
	string company;

public:
	Resume(string name) {
		this->name = name;
	}

	//设置个人信息
	void SetPersonalInfo(string sex, int age) {
		this->sex = sex;
		this->age = age;
	}

	//设置工作经历
	void SetWorkExperience(string timeArea, string company) {
		this->timeArea = timeArea;
		this->company = company;
	}

	//显示
	void Display() {
		cout << name << " " << sex << " " << age << endl;
		cout << "工作经历:" << timeArea << company << endl;
	}
};

//实现克隆简历
void test01()
{
	Resume a = Resume("大鸟");
	a.SetPersonalInfo("男", 29);
	a.SetWorkExperience("1998-2000", "XX公司");

	Resume b = Resume("大鸟");
	b.SetPersonalInfo("男", 29);
	b.SetWorkExperience("1998-2000", "XX公司");

	Resume c = Resume("大鸟");
	c.SetPersonalInfo("男", 29);
	c.SetWorkExperience("1998-2000", "XX公司");

	a.Display();
	b.Display();
	c.Display();
}

void test02()
{
	Resume* a = new Resume("大鸟");
	a->SetPersonalInfo("男", 29);
	a->SetWorkExperience("1998-2000", "XX公司");

	Resume* b = a;

	Resume* c = a;

	a->Display();
	b->Display();
	c->Display();

	delete a;
	delete b;
	delete c;
}

int main()
{
	test01();
	cout << "-----------------------" << endl;
	test02();

	system("pause");
	return 0;
}

test01 三份简历需要三次实例化,比较麻烦

test02 其实是传引用,而不是传值。这样做是在b、c纸上写着简历在a处一样,没有实际内容

原型模式

UML类图

代码实现

#include <iostream>
using namespace std;

//原型类
class Person {
public:
	virtual Person* clone() = 0;
};

//简历类
class Resume : public Person {
private:
	string name;
	string sex;
	int age;
	string timeArea;
	string company;

public:
	Resume() {};
	Resume(string name) {
		this->name = name;
	}

	//设置个人信息
	void SetPersonalInfo(string sex, int age) {
		this->sex = sex;
		this->age = age;
	}

	//设置工作经历
	void SetWorkExperience(string timeArea, string company) {
		this->timeArea = timeArea;
		this->company = company;
	}

	//显示
	void Display() {
		cout << name << " " << sex << " " << age << endl;
		cout << "工作经历:" << timeArea << " " << company << endl;
	}

	Person* clone() {
		Resume* obj = new Resume();
		*obj = *this;
		return obj;
	}
};

//客户端
void test()
{
	Resume* a = new Resume("大鸟");
	a->SetPersonalInfo("男", 29);
	a->SetWorkExperience("1998-2000", "XX公司");

	Resume* b = (Resume*)a->clone();
	Resume* c = (Resume*)a->clone();

	a->Display();
	b->Display();
	c->Display();

	delete a;
	delete b;
	delete c;
}

int main()
{
	test();

	system("pause");
	return 0;
}

只需要调用Clone方法就可以实现新简历的生成,并且可以再修改新简历的细节。等于是不用重新初始化对象,而是动态地获得对象运行时地状态。

一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这既隐藏了对象创建的细节,又对性能是大大的提高。

浅复制

如果“简历”类当中有一个“设置工作经历”的方法,现实设计中,一般会再有一个“工作经历”类,当中有“时间区间”和“公司名称”等属性,“简历”类直接调用这个对象。

UML类图

 代码实现

//简历的浅复制
#include <iostream>
#include <string>
using namespace std;

//原型类
class Person {
public:
	virtual Person* clone() = 0;
};

//工作经历类
class WorkExperence {
public:
	WorkExperence() {};
	~WorkExperence() {};
	WorkExperence(string workDate, string company) {
		this->company = company;
		this->workDate = workDate;
	}

	string workDate;
	string company;
};

//简历类
class Resume : public Person {
private:
	string name;
	string sex;
	int age;
	WorkExperence* work;

public:
	Resume() {};
	Resume(string name) {
		this->name = name;
		work = new WorkExperence();
	}

	//设置个人信息
	void SetPersonalInfo(string sex, int age) {
		this->sex = sex;
		this->age = age;
	}

	//设置工作经历
	void SetWorkExperience(string workDate, string company) {
		work->company = company;
		work->workDate = workDate;
	}

	//显示
	void Display() {
		cout << name << " " << sex << " " << age << endl;
		cout << "工作经历:" << work->workDate <<" " << work->company << endl;
	}

	Person* clone() {
		Resume* obj = new Resume();
		*obj = *this;
		return obj;
	}
};

//客户端
void test()
{
	Resume* a = new Resume("大鸟");
	a->SetPersonalInfo("男", 29);
	a->SetWorkExperience("1998-2000", "AA公司");

	Resume* b = (Resume*)a->clone();
	b->SetWorkExperience("1998-2000", "BB公司");

	Resume* c = (Resume*)a->clone();
	c->SetWorkExperience("1998-2000", "CC公司");

	a->Display();
	b->Display();
	c->Display();

	delete a;
	delete b;
	delete c;
}

int main()
{
	test();

	system("pause");
	return 0;
}

浅表复制对于值类型没有问题,对于引用类型,只是复制了引用,对引用的对象还是指向了原来的对象。

深复制

UML类图

 代码实现

//简历的浅复制
#include <iostream>
#include <string>
using namespace std;

//原型类
class Person {
public:
	virtual Person* clone() = 0;
};

//工作经历类
class WorkExperience : public Person {
public:
	WorkExperience() {};
	~WorkExperience() {};
	WorkExperience(string workDate, string company) {
		this->company = company;
		this->workDate = workDate;
	}
	//深拷贝--拷贝构造函数,使用引用
	WorkExperience(const WorkExperience& r) {
		workDate = r.workDate;
		company = r.company;
	}

	//“工作经历”类实现克隆方法
	Person* clone() {
		return new WorkExperience(*this); //调用拷贝构造函数
	}

	string workDate;
	string company;
};

//简历类
class Resume : public Person {
private:
	string name;
	string sex;
	int age;
	WorkExperience* work;

public:
	Resume() {};
	Resume(string name) {
		this->name = name;
		work = new WorkExperience();
	}
private:
	Resume(WorkExperience* _work) {
		//提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据
		this->work = (WorkExperience*)_work->clone();
	}

public:
	//设置个人信息
	void SetPersonalInfo(string sex, int age) {
		this->sex = sex;
		this->age = age;
	}

	//设置工作经历
	void SetWorkExperience(string workDate, string company) {
		work->company = company;
		work->workDate = workDate;
	}

	//显示
	void Display() {
		cout << name << " " << sex << " " << age << endl;
		cout << "工作经历:" << work->workDate << " " << work->company << endl;
	}

	Person* clone() {
		//调用私有的构造方法,让“工作经历”克隆完成,然后再给这个“简历”对象的相关字段赋值
		//最终返回一个深复制的简历对象
		Resume* obj = new Resume(this->work);
		obj->age = this->age;
		obj->name = this->name;
		obj->sex = this->sex;
		return obj;
	}
};

//客户端
void test()
{
	Resume* a = new Resume("大鸟");
	a->SetPersonalInfo("男", 29);
	a->SetWorkExperience("1998-2000", "AA公司");

	Resume* b = (Resume*)a->clone(); 
	b->SetWorkExperience("1998-2000", "BB公司");

	Resume* c = (Resume*)a->clone();
	c->SetWorkExperience("1998-2000", "CC公司");

	a->Display();
	b->Display();
	c->Display();

	delete a;
	delete b;
	delete c;
}

int main()
{
	test();

	system("pause");
	return 0;
}

浅复制中被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍指向原来的对象。深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

posted @ 2022-09-07 16:59  KYZH  阅读(88)  评论(0)    收藏  举报