上篇文章,介紹了《大話設(shè)計(jì)模式》的第8章——工廠方法。
本篇,來(lái)介紹《大話設(shè)計(jì)模式》的第9章——原型模式。并通過(guò)C++代碼實(shí)現(xiàn)實(shí)例代碼的功能。
1 原型模式
原型模式(Prototype):用原型實(shí)例指定創(chuàng)建對(duì)象的種類(lèi),并且通過(guò)拷貝這些原型創(chuàng)建新的對(duì)象。
原型模式的類(lèi)圖如下:
- Client:讓一個(gè)原型克隆自身從而創(chuàng)建一個(gè)新的對(duì)象Prototype:原型類(lèi),聲明一個(gè)克隆自身的接口ConcreatePrototype:具體原型類(lèi),實(shí)現(xiàn)一個(gè)克隆自身的操作
2 實(shí)例
背景:書(shū)中小故事,小菜要去找工作,準(zhǔn)備了很厚一疊簡(jiǎn)歷,大鳥(niǎo)在感慨他那時(shí)找工作的時(shí)候,都是手寫(xiě)簡(jiǎn)歷,現(xiàn)在印簡(jiǎn)歷就像印草紙一樣,由此聯(lián)想到代碼中的復(fù)制粘貼。
題目:用代碼的形式來(lái)實(shí)現(xiàn)簡(jiǎn)歷類(lèi)的功能,要求必須要有姓名,可以設(shè)置性別和年齡,可以設(shè)置工作經(jīng)歷,最終需要寫(xiě)三份簡(jiǎn)歷。
2.1 版本一:?jiǎn)我缓?jiǎn)歷類(lèi)
版本一的實(shí)現(xiàn)比較簡(jiǎn)單,僅設(shè)計(jì)一個(gè)簡(jiǎn)歷類(lèi)。
2.1.1 簡(jiǎn)歷類(lèi)
簡(jiǎn)歷類(lèi)的實(shí)現(xiàn)如下:
- 簡(jiǎn)歷類(lèi)構(gòu)造時(shí)傳入姓名作為參數(shù)調(diào)用設(shè)置個(gè)人信息方法SetPersonalInfo,可設(shè)置性別和年齡調(diào)用設(shè)置工作經(jīng)歷方法SetWorkExperience,可設(shè)置工作時(shí)間與工作的公司調(diào)用顯示方法Display,可顯示簡(jiǎn)歷的完整內(nèi)容
// 簡(jiǎn)歷類(lèi)
class Resume
{
public:
Resume(std::string name)
{
m_name = name;
}
// 設(shè)置個(gè)人信息
void SetPersonalInfo(std::string sex, int age)
{
m_sex = sex;
m_iAge = age;
}
// 設(shè)置工作經(jīng)歷
void SetWorkExperience(std::string timeArea, std::string company)
{
m_timeArea = timeArea;
m_company = company;
}
// 顯示
void Display()
{
printf("%s %s %dn", m_name.c_str(), m_sex.c_str(), m_iAge);
printf("工作經(jīng)歷:%s %sn", m_timeArea.c_str(), m_company.c_str());
}
private:
std::string m_name;
std::string m_sex;
int m_iAge;
std::string m_timeArea;
std::string m_company;
};
2.1.2 主函數(shù)
首先,實(shí)例化三份簡(jiǎn)歷,并分別設(shè)置具體的內(nèi)容,
然后,就可以調(diào)用展示接口來(lái)顯示出來(lái)了。
int main()
{
// 實(shí)例化三份簡(jiǎn)歷
Resume a = Resume("大鳥(niǎo)");
a.SetPersonalInfo("男", 29);
a.SetWorkExperience("2018-2020", "XX公司");
Resume b = Resume("大鳥(niǎo)");
b.SetPersonalInfo("男", 29);
b.SetWorkExperience("2018-2020", "XX公司");
Resume c = Resume("大鳥(niǎo)");
c.SetPersonalInfo("男", 29);
c.SetWorkExperience("2018-2020", "XX公司");
// 顯示出來(lái)
a.Display();
b.Display();
c.Display();
return 0;
}
代碼運(yùn)行效果如下:
下面來(lái)看版本二。
2.2 版本二:原型模式
版本二,使用原型模型,設(shè)計(jì)了一個(gè)簡(jiǎn)歷原型類(lèi),定義了簡(jiǎn)歷所具有的基本信息及接口,簡(jiǎn)歷類(lèi)則繼承簡(jiǎn)歷原型類(lèi),
另外,工作經(jīng)歷設(shè)計(jì)為一個(gè)單獨(dú)類(lèi),通過(guò)組合方式,作為簡(jiǎn)歷類(lèi)的一部分。
注1:書(shū)中代碼使用的C#,C#中有MemberwiseClone方法進(jìn)行拷貝,而C++中無(wú)此方法,因此需要重新實(shí)現(xiàn)一個(gè)Clone方法。
注2:對(duì)對(duì)象進(jìn)行拷貝時(shí),會(huì)涉及到淺拷貝與深拷貝的概念,而MemberwiseClone方法對(duì)于引用類(lèi)型的對(duì)象,復(fù)制的是引用而不是復(fù)制對(duì)象,這樣就會(huì)帶來(lái)修改了復(fù)制后的對(duì)象,原對(duì)象也會(huì)被修改。因此,書(shū)中例子講工作經(jīng)歷單獨(dú)拎出來(lái)作為一個(gè)類(lèi),拷貝簡(jiǎn)歷時(shí),簡(jiǎn)歷中的工作經(jīng)歷將為引用類(lèi)型,以此來(lái)對(duì)比演示淺拷貝帶來(lái)的影響。解決方法就是改為深拷貝,在工作經(jīng)歷類(lèi)的內(nèi)部也實(shí)現(xiàn)一個(gè)Clone方法。
2.2.1 工作經(jīng)歷類(lèi)、簡(jiǎn)歷原型類(lèi)與簡(jiǎn)歷類(lèi)
這里需要實(shí)現(xiàn)三個(gè)類(lèi):
- 工作經(jīng)歷類(lèi):作為簡(jiǎn)歷的一部分,實(shí)現(xiàn)工作時(shí)間與對(duì)應(yīng)的工作公司的信息,并提供克隆接口簡(jiǎn)歷原型類(lèi):一個(gè)抽象類(lèi),定義了簡(jiǎn)歷所具有的基本信息及接口,并提供克隆接口,實(shí)現(xiàn)簡(jiǎn)歷克隆簡(jiǎn)歷類(lèi):繼承簡(jiǎn)歷原型類(lèi),并實(shí)現(xiàn)簡(jiǎn)歷原型中定義的方法
// 工作經(jīng)歷
class WorkExperience
{
public:
WorkExperience() {}
~WorkExperience(){}
WorkExperience(WorkExperience *work)
{
this->m_timeArea = work->m_timeArea;
this->m_company = work->m_company;
}
// 設(shè)置/獲取工作時(shí)間
void SetWorkTiemArea(std::string timeArea)
{
m_timeArea = timeArea;
}
std::string GetWorkTiemArea()
{
return m_timeArea;
}
// 設(shè)置/獲取工作公司
void SetWorkCompany(std::string company)
{
m_company = company;
}
std::string GetWorkCompany()
{
return m_company;
}
// Clone
WorkExperience *Clone()
{
return new WorkExperience(this);
}
private:
std::string m_timeArea;
std::string m_company;
};
// 簡(jiǎn)歷原型類(lèi)
class Prototype
{
public:
virtual void SetPersonalInfo(std::string sex, int age) = 0;
virtual void Display() = 0;
virtual Prototype *Clone() = 0;
protected:
std::string m_name;
std::string m_sex;
int m_iAge;
std::string m_timeArea;
std::string m_company;
};
// 簡(jiǎn)歷類(lèi)
class Resume : public Prototype
{
public:
Resume(std::string name)
{
m_name = name;
m_pWork = new WorkExperience();
}
~Resume()
{
if (m_pWork)
{
delete m_pWork;
}
}
// 設(shè)置個(gè)人信息
void SetPersonalInfo(std::string sex, int age)
{
m_sex = sex;
m_iAge = age;
}
// 設(shè)置工作經(jīng)歷
void SetWorkExperience(std::string timeArea, std::string company)
{
m_pWork->SetWorkTiemArea(timeArea);
m_pWork->SetWorkCompany(company);
}
// 顯示
void Display()
{
printf("%s %s %dn", m_name.c_str(), m_sex.c_str(), m_iAge);
printf("工作經(jīng)歷:%s %sn", m_pWork->GetWorkTiemArea().c_str(), m_pWork->GetWorkCompany().c_str());
}
Resume *Clone()
{
Resume *pClone = new Resume(m_name);
pClone->SetPersonalInfo(m_sex, m_iAge);
return pClone;
}
private:
WorkExperience *m_pWork;
};
2.2.2 主函數(shù)
首先,實(shí)例化了一個(gè)簡(jiǎn)歷A,并設(shè)置一些基礎(chǔ)信息。
然后,通過(guò)克隆的方式,產(chǎn)生簡(jiǎn)歷B與簡(jiǎn)歷C,并對(duì)簡(jiǎn)歷B與簡(jiǎn)歷C進(jìn)行個(gè)性化修改。
最后,調(diào)用顯示接口顯示簡(jiǎn)歷的內(nèi)容。
int main()
{
// 實(shí)例化三份簡(jiǎn)歷
Resume a = Resume("大鳥(niǎo)");
a.SetPersonalInfo("男", 29);
a.SetWorkExperience("2018-2020", "XX公司");
Resume *b = a.Clone();
b->SetWorkExperience("2018-2021", "YY公司");
Resume *c = a.Clone();
c->SetPersonalInfo("男", 24);
c->SetWorkExperience("2018-2022", "ZZ公司");
// 顯示出來(lái)
a.Display();
b->Display();
c->Display();
delete b;
delete c;
return 0;
}
代碼運(yùn)行效果如下:
原型模式的主要特點(diǎn)在于設(shè)計(jì)了一個(gè)克隆方法,通過(guò)克隆,將當(dāng)前對(duì)象的當(dāng)前狀態(tài)做一個(gè)拷貝,形成一個(gè)新的對(duì)象,注意體會(huì)這里的“當(dāng)前狀態(tài)”,它不是初始狀態(tài),而是在程序運(yùn)行到某一時(shí)刻時(shí)其內(nèi)部屬性的最新?tīng)顟B(tài)。
總結(jié)
本篇介紹了設(shè)計(jì)模式中的原型模式,并通過(guò)簡(jiǎn)歷編寫(xiě)的實(shí)例,使用C++編程,來(lái)演示原型模式的使用。
文章推薦