一、描述:
关于这个模式,突然想到了小时候看的《西游记》,齐天大圣孙悟空再发飙的时候可以通过自己头上的 3 根毛立马复制出来成千上万的孙悟空,对付小妖怪很管用(数量最重要)。
Prototype 模式也正是提供了自我复制的功能,就是说新对象的创建可以通过已有对象进行创建。在 C++中拷贝构造函数(Copy Constructor)曾经是很对程序员的噩梦,浅层拷贝和深层拷贝的魔魇也是很多程序员在面试时候的快餐和系统崩溃时候的根源之一。
Prototype 模式典型的结构图为:
实现和具体的实现语言相关,在 C++中我们将通过拷贝构造函数实现之。
二、实例:
1.描述:
今天我们来讲原型模式,这个模式的简单程度是仅次于单例模式和迭代器模式,非常简单,但是要使用好这个模式还有很多注意事项。我们通过一个例子来解释一下什么是原型模式。现在电子账单越来越流行了,比如你的信用卡,到月初的时候银行就会发一份电子邮件到你邮箱中,说你这个月消费了多少,什么时候消费的,积分是多少等等,这个是每个月发一次,但是还有一种也是银行发的邮件你肯定有印象:广告信,现在各大银行的信用卡部门都在拉拢客户,电子邮件是一种廉价、快捷的通讯方式,你用纸质的广告信那个费用多高呀,比如我今天推出一个信用卡刷卡抽奖活动,通过电子账单系统可以一个晚上发送给 600 万客户,为什么要用电子账单系统呢?直接找个发垃圾邮件不就解决问题了吗?是个好主意,但是这个方案在金融行业是行不通的,银行发这种邮件是有要求的,一是一般银行都要求个性化服务,发过去的邮件上总有一些个人信息吧,比如“XX 先生”,“XX 女士”等等,二是邮件的到达率有一定的要求,由于大批量的发送邮件会被接收方邮件服务器误认是垃圾邮件,因此在邮件头要增加一些伪造数据,以规避被反垃圾邮件引擎误认为是垃圾邮件;从这两方面考虑广告信的发送也是电子账单系统(电子账单系统一般包括:账单分析、账单生成器、广告信管理、发送队列管理、发送机、退信处理、报表管理等)的一个子功能,我们今天就来考虑一下广告信这个模块是怎么开发的。那既然是广告信,肯定需要一个模版,然后再从数据库中把客户的信息一个一个的取出,放到模版中生成一份完整的邮件,然后扔给发送机进行发送处理,我们来看类图:
2.本人工程目录:
在类图中 AdvTemplate 是广告信的模板,一般都是从数据库取出,生成一个 BO 或者是 DTO,我们这里使用一个静态的值来做代表;Mail 类是一封邮件类,发送机发送的就是这个类,我们先来看看我们的程序结构:
3.实例代码:
广告信的模板类AdvTemplate
AdvTemplate.h
#pragma once
#include <iostream>
using std::string;
class CAdvTemplate
{
public:
CAdvTemplate(void);
~CAdvTemplate(void);
string GetAdvSubject();
string GetAdvContext();
private:
string m_advSubject;
string m_advContext;
};
AdvTemplate.cpp
#include "AdvTemplate.h"
CAdvTemplate::CAdvTemplate(void)
{
this->m_advSubject = "XX银行国庆信用卡抽奖活动";
this->m_advContext = "国庆抽奖活动通知:只要刷卡就送你1百万!……";
}
CAdvTemplate::~CAdvTemplate(void)
{
}
//取得广告信的名称
string CAdvTemplate::GetAdvSubject()
{
return this->m_advSubject;
}
//取得广告信的名称
string CAdvTemplate::GetAdvContext()
{
return this->m_advContext;
}
增加了一个 ICloneableNow接口, 同时在 Mail 类中重写了 clone()方法
注:增加接口的原因,是为了避免 sendMail 修改为多线程后的存在安全性问题。
ICloneableNow.h
#pragma once
class CMail;
class ICloneableNow
{
public:
ICloneableNow(void)
{
}
virtual ~ICloneableNow(void)
{
}
virtual CMail * Clone() = 0;
};
邮件类 Mail
Mail.h
#pragma once
#include "ICloneableNow.h"
#include "AdvTemplate.h"
#include <iostream>
using std::string;
class CMail :
public ICloneableNow
{
public:
CMail(CAdvTemplate *pAdvTmpl);
~CMail(void);
string GetReceiver();
void SetReceiver(string receiver);
string GetSubject();
void SetSubject(string subject);
string GetAppellation();
void SetAppellation(string appellation);
string GetContxt();
void SetContxt(string contxt);
string GetTail();
void SetTail(string tail);
CMail * Clone();
private:
string m_receiver; //收件人
string m_subject; //邮件名称
string m_appellation; //称谓
string m_contxt; //邮件内容
string m_tail; //邮件的尾部,一般都是加上“XXX版权所有”等信息
};
Mail.cpp
#include "Mail.h"
CMail::CMail(CAdvTemplate *pAdvTmpl)
{
this->m_contxt = pAdvTmpl->GetAdvContext();
this->m_subject = pAdvTmpl->GetAdvSubject();
}
CMail::~CMail(void)
{
}
string CMail::GetReceiver()
{
return m_receiver;
}
void CMail::SetReceiver(string receiver)
{
m_receiver = receiver;
}
string CMail::GetSubject()
{
return m_subject;
}
void CMail::SetSubject(string subject)
{
m_subject = subject;
}
string CMail::GetAppellation()
{
return m_appellation;
}
void CMail::SetAppellation(string appellation)
{
m_appellation = appellation;
}
string CMail::GetContxt()
{
return m_contxt;
}
void CMail::SetContxt(string contxt)
{
m_contxt = contxt;
}
string CMail::GetTail()
{
return m_tail;
}
void CMail::SetTail(string tail)
{
m_tail = tail;
}
CMail * CMail::Clone()
{
const CMail entity = *this;
CMail *pMail = new CMail(entity);
return pMail;
}
测试代码:
main.cpp
#include <stdio.h>
#include "Mail.h"
#include "AdvTemplate.h"
#include <iostream>
#include <time.h>
using std::cout;
using std::endl;
using std::string;
//---------------------自定义的随机数发生器----------------------------------
int rand_int(int min,int max) //产生字符
{
int temp=rand()%max;
while(temp<rand()%min)
temp=rand()%max;
return temp;
}
int GetRand1()
{
srand(time(0));
for(int i=0;i <=9;i++)
{
int ii = rand();
cout << ii << endl;
return ii;
}
return 0;
}
int GetRand2(int previous)
{
//time_t t;
srand((unsigned int)time(NULL) + previous);
//srand((unsigned)time(0));
for(int i=0; i <100; i++)
{
//int j=1+(int)(52.0*rand()/(RAND_MAX+1.0));
//int j = 1+(int)((rand()/(double)RAND_MAX)*36); //求随机值
//int j=1+(int)(10.0*rand()/(RAND_MAX+1.0));
int j = rand()%52;
//int ii = rand()%10000;//
if (j != previous)
{
// cout << j <<endl;
return j;
}
}
return 0;
}
string GetRandString(int count)
{
char *pSource = "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *pRet = new char[count + 1];
int index = static_cast<int>(time(NULL));
for (int i = 0; i < count; i++)
{
index = rand_int(5, 30);
//index = GetRand2(index);
pRet[i] = *(pSource + index);
index += index;
}
pRet[count] = '\0';
//cout << pRet << "--" << endl;
string ret(pRet);
delete pRet;
pRet = NULL;
return ret;
}
void SendMail(CMail mail)
{
cout << " 主题:" << mail.GetSubject().c_str();
// cout << " 称谓:" << mail.GetAppellation().c_str();
cout << " 收件人:" << mail.GetReceiver().c_str();
cout << " ......发送成功!" << endl;
}
void DoIt()
{
int i = 0;
int count = 3;
CAdvTemplate tmpl;
CMail mail(&tmpl);
mail.SetTail("XX银行版权所有");
while(i < count)
{
CMail *pMail = &mail;
CMail *pCloneMail = mail.Clone();
string appellation = GetRandString(8);
appellation.append(" 先生(女士) ");
pCloneMail->SetAppellation(appellation);
string receiver = GetRandString(5);
receiver.append("@");
receiver.append(GetRandString(8));
receiver.append(".com");
pCloneMail->SetReceiver(receiver);
SendMail(*pCloneMail);
delete pCloneMail;
pCloneMail = NULL;
pMail = NULL;
i++;
}
}
const int SIZE_CHAR = 32;
const char CCH[] = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
int main(int argc, const char * argv[])
{
DoIt();
// insert code here...
printf("Hello, World!\n");
return 0;
}
结果如下: