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;
}
最终实现了需求