在西游记中,我们常看到孙悟空用自己的猴毛变出很多个特征跟自己一模一样的"孙悟空"来, 可能仅仅是名字不一样,孙悟空二弟、孙悟空三弟、孙悟空四弟,除了名字不一样外,其他的特征完全一模一样,这个通过孙悟空创建出的多个跟自己一模一样的克隆品,在设计模式里头,我们称之为:原型模式
在开始讲解之前,还是以一个场景来描述下这个需求,在我们工作中,常常要写日报,一个小组内的成员日报格式一样,那么久很有可能两个人当天做的工作时一样的,那么体现在日报中的信息,仅仅是名字不同。
将这个设计成类,可以设计为如下(包含姓名、日期、工作内容)
class WeekLog
{
private:
string m_name; //姓名
string m_date; //日期
string m_content; //工作内容
public:
WeekLog(string name,string date,string content)
{
m_name = name;
m_date = date;
m_content = content;
}
string setName(string name)
{
m_name = name;
}
string setDate(string date)
{
m_date = date;
}
string setContent(string content)
{
m_content = content;
}
string getName()
{
return m_name;
}
string getDate()
{
return m_date;
}
string getContent()
{
return m_content;
}
};
那么可以按照如下方式使用这个类
int main(int argc, char* argv[])
{
//Tom与Jack的日报中日期、工作内容都一样
WeekLog TomWeekLog("Tom","20190427","Bug Fix!");
WeekLog JackWeekLog("Jack","20190427","Bug Fix!");
cout << TomWeekLog.getName() << endl;
cout << TomWeekLog.getDate() << endl;
cout << TomWeekLog.getContent() << endl;
cout << JackWeekLog.getName() << endl;
cout << JackWeekLog.getDate() << endl;
cout << JackWeekLog.getContent() << endl;
return 0;
}
这么使用当然是没问题的。
但是注意上边Tom与Jack的日报信息,除了名字不同外,日期跟工作内容都是相同的,而在 定义Jack的日报信息时,把所有的内容都重设定了一遍,这显得有点累赘了。
为了解决这个问题,我们引入了原型设计模式:在类中增加一个clone函数,自己new自己后返回一个新的自己。(想想孙悟空自己复制自己)
代码实现则很简单,如下:
class WeekLog
{
private:
string m_name;
string m_date;
string m_content;
public:
WeekLog(string name,string date,string content)
{
m_name = name;
m_date = date;
m_content = content;
}
WeekLog(const WeekLog& obj) //拷贝构造函数
{
m_name = obj.m_name;
m_date = obj.m_date;
m_content = obj.m_content;
}
WeekLog& operator=(const WeekLog& obj) //赋值构造函数
{
if(this != &obj)
{
m_name = obj.m_name;
m_date = obj.m_date;
m_content = obj.m_content;
}
return *this;
}
virtual string setName(string name)
{
m_name = name;
}
virtual string setDate(string date)
{
m_date = date;
}
virtual string setContent(string content)
{
m_content = content;
}
virtual string getName()
{
return m_name;
}
virtual string getDate()
{
return m_date;
}
virtual string getContent()
{
return m_content;
}
//克隆操作,返回一个new 后的自己
WeekLog* clone()
{
return new WeekLog(*this); //这里使用拷贝构造函数,即new后得到的对象跟原对象信息一致
}
};
下边来使用下:
int main(int argc, char* argv[])
{
WeekLog TomWeekLog("Tom","20190427","Bug Fix!");
WeekLog* JackWeekLog = TomWeekLog.clone(); //从现有对象克隆一份
JackWeekLog->setName("Jack"); //修改下名字即可
cout << TomWeekLog.getName() << endl;
cout << TomWeekLog.getDate() << endl;
cout << TomWeekLog.getContent() << endl;
cout << JackWeekLog->getName() << endl;
cout << JackWeekLog->getDate() << endl;
cout << JackWeekLog->getContent() << endl;
delete JackWeekLog;
return 0;
}
编译运行
可以看到,只有名字不一样,其他信息都是一样的,并且在生成Jack的日报时,也不需要重设所有项