大话设计模式5—原型模式(简历复印)

1.需求:简历复印

设计一个简历类,要求包含姓名、性别、年龄,此外能够设计工作经历(公司名和工作时间),最终需要一个人三份不同的简历,如下图所示。
在这里插入图片描述

2.普通实现

(1)常规做法

设计一个简历类,简历类包含的变量有姓名、性别、年龄、公司名、工作时间,构造函数负责初始化姓名,此外还有三个成员函数分别进行设置个人信息、设置工作经历和打印简历。那么题设需求只需要实例化三次就行。
Resume类

#ifndef RESUME_H
#define RESUME_H
#include<string>
using namespace std;
class Resume {
private:
	string m_name;
	string m_sex;
	int m_age;
	string m_company;
	string m_time_area;
public:
	Resume(string name);
	void SetWorkExperience(string company, string time_area);
	void SetInfo(string sex, int age);
	void PrintResume();
};
#endif

Resume类实现

#include"Resume.h"
#include<iostream>
using namespace std;
Resume::Resume(string name) :m_name(name)
{
}

void Resume::SetInfo(string sex, int age)
{
	m_sex = sex;
	m_age = age;
}

void Resume::SetWorkExperience(string company, string time_area)
{
	m_company = company;
	m_time_area = time_area;
}

void Resume::PrintResume()
{
	cout << m_name << " , " << m_sex << "," << m_age << endl
		<< "工作经历: " << m_time_area << " , " << m_company << endl;
}

main函数

#include"Resume.h"

int main()
{
	Resume* resume1 = new Resume("xiaoxuan");
	resume1->SetInfo("男", 25);
	resume1->SetWorkExperience("nwpu", "2018-2021");
	resume1->PrintResume();

	Resume* resume2 = new Resume("xiaoxuan");
	resume2->SetInfo("男", 25);
	resume2->SetWorkExperience("xiaomi", "2021-2032");
	resume2->PrintResume();

	Resume* resume3 = new Resume("xiaoxuan");
	resume3->SetInfo("男", 25);
	resume3->SetWorkExperience("daiye", "2032-...");
	resume3->PrintResume();
	
	return 0;
}

打印输出如下,好像没什么问题
在这里插入图片描述

分析缺点:实例化次数太多,假如需要二十份简历则要实例化二十次。此外,假如某一个部分写错了,也需要Set修改二十次才行。

(2)憨批做法

知道了常规做法的问题所在,想法子减少实例化次数,考虑修改main函数:直接使用指针进行拷贝
在main函数中改为

	Resume* resume1 = new Resume("xiaoxuan");
	resume1->SetInfo("男", 25);
	resume1->SetWorkExperience("nwpu", "2018-2021");
	resume1->PrintResume();

	Resume* test = resume1;
	test->PrintResume();

打印输出好像没错

在这里插入图片描述
但是,如果我修改年龄再打印看看

	resume1->SetInfo("男", 30);
	resume1->PrintResume();
	test->PrintResume();

在这里插入图片描述
发现年龄都被修改了!!!这种方法之所以称为憨批方法,因为只是将resume1和test指针指向一块内存空间,也就是所谓的浅拷贝,改一个数据自然两个指针的内容都改变了。实际是错误的!!
那么,如何才能深拷贝的情况下,尽量少的实例化完成简历拷贝呢?请看原型模式

3.原型模式

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。也就是说从一个对象创建另一个可定制的对象,而且不需要知道任何细节
在这里插入图片描述

4.原型模式实现

为什么说简历复制可以使用原型模式呢?我们仔细观察发现,简历中年龄、性别这些东西所有简历都是相同的,只有工作经历需要修改,那么每次年龄、性别都可以直接克隆,对于工作经历根据需要单独修改就可以。

为此,设计两个类:Resume类和WorkExperience类,这两个类各自提供一个复制的接口。
WorkExperience类实现比较简单,数据成员有公司名和工作时间两个,成员函数提供获取和更改的功能。此外,还增加一个clone()接口。

#ifndef WORKEXPERIENCE_H
#define WORKEXPERIENCE_H

#include<string>
using namespace std;
class WorkExperience {
public:
	void SetCompany(string company);
	void SetWorkDate(string work_date);
	string GetCompany();
	string GetWorkDate();
	WorkExperience* clone();
private:
	string m_company;
	string m_work_date;
};
#endif

clone()接口可以深拷贝WorkExperience类的对象,也就是申请一块内存空间,再复制,具体实现如下。

WorkExperience* WorkExperience::clone()
{
	WorkExperience* new_work_experience = new WorkExperience();
	new_work_experience->SetCompany(m_company);
	new_work_experience->SetWorkDate(m_work_date);
	return new_work_experience;

}

整个WorkExperience类实现如下

#include "WorkExperience.h"

void WorkExperience::SetCompany(string company)
{
	m_company = company;
}

void WorkExperience::SetWorkDate(string work_date)
{
	m_work_date = work_date;
}

string WorkExperience::GetCompany()
{
	return m_company;
}

string WorkExperience::GetWorkDate()
{
	return m_work_date;
}

WorkExperience* WorkExperience::clone()
{
	WorkExperience* new_work_experience = new WorkExperience();
	new_work_experience->SetCompany(m_company);
	new_work_experience->SetWorkDate(m_work_date);
	return new_work_experience;

}

接下来我们看Resume类,共有四个数据成员,姓名、性别、年龄、工作经历的指针,以及构造函数、析构函数、设置个人信息、工作经历和clone接口。

#ifndef RESUME_H
#define RESUME_H
#include<string>
#include<iostream>
#include"WorkExperience.h"
using namespace std;
class Resume {
private:
	string m_name;
	string m_sex;
	int m_age;
	WorkExperience *m_work_experience;
public:
	Resume() {};
	Resume(string name);
	~Resume();
	void SetInfo(string sex,int age);
	void SetWorkExperience(string company,string work_date);
	void PrintResume();
	Resume* clone();
};
#endif

注意下Resume类的构造函数传入姓名,实例化简历,还需要为m_work_experience指针申请一块空间

Resume::Resume(string name)
{
	m_name = name;
	m_work_experience = new WorkExperience();
}

那么理所应当的析构函数负责回收空间

Resume::~Resume()
{
	delete m_work_experience;
}

Resume类的复制,具体来说既复制不需改变的年龄和性别,再通过调用WorkExperience中复制的接口复制工作经验。
先申请一块空间,再拷贝,注意新的m_work_experience指针指向的空间需要用WorkExperience类的clone接口来复制

Resume* Resume::clone()
{
	Resume* new_resume = new Resume(m_name);
	new_resume->SetInfo(m_sex, m_age);
	new_resume->m_work_experience = this->m_work_experience->clone();
	return new_resume;
}

其他的设置个人信息、设置工作经历比较简单跟以前一样。最后放下Resume类实现的代码

#include "Resume.h"

Resume::Resume(string name)
{
	m_name = name;
	m_work_experience = new WorkExperience();
}

Resume::~Resume()
{
	delete m_work_experience;
}

void Resume::SetInfo(string sex, int age)
{
	m_age = age;
	m_sex = sex;
}

void Resume::SetWorkExperience(string company,string work_date)
{
	m_work_experience->SetCompany(company);
	m_work_experience->SetWorkDate(work_date);
}

void Resume::PrintResume()
{
	cout << m_name << " , " << m_sex << " , " << m_age << endl
		<< "工作经历: " << m_work_experience->GetWorkDate() << " , " << m_work_experience->GetCompany() << endl;
}

Resume* Resume::clone()
{
	Resume* new_resume = new Resume(m_name);
	new_resume->SetInfo(m_sex, m_age);
	new_resume->m_work_experience = this->m_work_experience->clone();
	return new_resume;
}

main函数

#include"WorkExperience.h"
#include"Resume.h"

int main()
{
	Resume* resume1 = new Resume("xiaoxuan");
	resume1->SetInfo("男",25);
	resume1->SetWorkExperience("nwpu", "2018-2021");
	resume1->PrintResume();

	Resume* resume2 = resume1->clone();
	resume2->SetWorkExperience("xiaomi", "2021-2032");
	resume2->PrintResume();

	Resume* resume3 = resume2->clone();
	resume3->SetWorkExperience("daiye", "2032-...");
	resume3->PrintResume();

	return 0;
}

最终实现了需求
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值