(1)模板方法模式的本质:固定算法骨架
(2)模板方法模式的核心:处理某个流程的代码己经都具备,但是其中某些节点的代码不能确定。因此,将这些节点的代码实现转移给子类完成。即处理步骤父类中己经定义好,具体实现延迟到子类中定义。
(3)模板方法中的变与不变
①需要变化的地方都通过纯虚函数,把具体实现延迟到子类中。
②不变的部分,进行公共实现。
(4)好莱坞法则:Don’t call me, I’ll call you
①正常的控制结构:子类调用父类方法,这很正常因为子类继承了父类,所以是知道父类的。
②反向的控制结构:父类调用子类方法,因为父类是不可能知道子类的,所以这也是一种反向的控制结构。在C++中是通过虚函数实现的。
模板的写法
(1)模板方法:就是定义算法骨架的方法。如上例中的shop()
(2)具体的操作:在模板中直接实现的某些步骤方法,这些步骤的实现通常是固定的,不怎么会变化的,因此可以将其当作公共功能实现在模板中。如果不需子类访问这些函数,可以定义为private。子类需要访问定义为protected
(3)具体的AbstractClass操作:在模板中实现某些公共功能,可以提供给子类使用,一般不是具体的算法步骤的实现,而是一些辅助的公共功能。
(4)原语操作:就是在模板中定义的纯虚函数,通常是模板方法需要调用的操作,是必须的操作,而且在父类中还没办法确定下来如何实现,需要子类来真正实现的方法。
(5)钩子操作:在模板中定义,并提供默认实现的操作,这些方法通常被视为可扩展的点,但不是必须的,子类可以有选择地覆盖这些方法,以提供新的实现来扩展功能,这些函数一般被声明为virtual。
【编程实验】两种登录控制(普通用户和管理员)
//行为型模式——模板方式模式
//场景:两种登录控制(普通用户和管理员)
/*
说明:
1.普通用户和管理员是在数据库中是存储在不同的表里。此外管理员的
密码是加密的
2. 这两种角色登录的是不同模块,有不同的页面、不同的处理逻辑和不
同的数据存储。
登录控制的算法框架
1. 根据登录人员的编号去获取相应的数据
2. 获取对登录人员填写的密码进行加密后的数据,如果不需要加密,那就
直接返回登录人员填写的密码数据。(可选)
3. 判断登录人员填写的数据和从数据库中获取的数据是否匹配
*/
#include
#include
using namespace std;
//*********************************辅助类*************************
//封装进行登录控制所需要的数据(即前台页面填写的用户数据信息)
//本例为了简单,登录时的信息模型和数据表中用户信息的数据模型共用下面的数据结构
class CLoginModel{
private:
string strAcc;//登录账号
string strPwd;//登录密码
string strQuestion;//密码验证问题
string strAnswer;//密码验证答案
public:
string& GetAcc(){return strAcc;}
string& GetPwd(){return strPwd;}
};
//登录控制的模板,也是登录控制算法的骨架
class CLoginTemplate{
protected://专题方法
//根据登录编号从数据库中找到相应的用户信号
virtual CLoginModel* FindUserByAcc(string acc) = 0;
//对密码进行加密,提供默认的实现,子类可以去覆盖
virtual string EncrptPwd(string pwd){return pwd;}
private://公共方法
//判断用户填写的登录数据和数据库的数据是否匹配
bool Match(CLoginModel* curr, CLoginModel* db){
return ((curr->GetAcc() == db->GetAcc())&(curr->GetPwd() == db->GetPwd()));
}
public:
bool Login(CLoginModel* curr){
bool bResult = false;
//1.根据登录人员的编号从数据库中获取相应用户信息
CLoginModel* db = FindUserByAcc(curr->GetAcc());
if(db != NULL){
//2. 对密码进行加密后,把加密后的密码设置回到登录数据模型中
curr->GetPwd() = EncrptPwd(curr->GetPwd());
//3. 判断是否匹配
bResult = Match(curr, db);
delete db;
}
return bResult;
}
virtual ~CLoginTemplate(){}
};
//普通用户登录控制的逻辑处理
class CNormalLogin : public CLoginTemplate{
protected:
CLoginModel* FindUserByAcc(string acc){
//这里省略了数据访问,仅做示意
//返回一个有默认的数据对象
CLoginModel* pUser = new CLoginModel();
pUser->GetAcc() = acc; pUser->GetPwd() = "NormalPwd";
return pUser;
}
};
//管理员登录的控制逻辑处理
class CAdminLogin : public CLoginTemplate{
protected:
CLoginModel* FindUserByAcc(string acc){
//这里省略了数据访问,仅做示意
//返回一个有默认的数据对象
CLoginModel* pUser = new CLoginModel();
pUser->GetAcc() = acc; pUser->GetPwd() = "MD5(AdminPwd)";
return pUser;
}
//对密码以MD5的方式进行加密
string EncrptPwd(string pwd){return ("MD5(" + pwd + ")");}
};
void main()
{
//准备登录人员的信息
CLoginModel oNormal;//普通用户
oNormal.GetAcc() = "Normal"; oNormal.GetPwd() = "NormalPwd";
CLoginModel oAdmin;//管理员
oAdmin.GetAcc() = "Admin"; oAdmin.GetPwd() = "AdminPwd";
//模拟登录系统
CLoginTemplate* pAdminLogin = new CAdminLogin();
if(pAdminLogin != NULL){
bool bOk = pAdminLogin->Login(&oAdmin);//登录测试
cout << "用户(" << oAdmin.GetAcc() << ")登录管理员后台:" << (bOk ? "成功" : "失败") << endl;
delete pAdminLogin; pAdminLogin = NULL;
}
CLoginTemplate* pNormalLogin = new CNormalLogin();
if(pNormalLogin != NULL){
bool bOk = pNormalLogin->Login(&oNormal);//登录测试
cout << "用户(" << oNormal.GetAcc() << ")登录普通用户界面:" << (bOk ? "成功" : "失败") << endl;
delete pNormalLogin; pNormalLogin = NULL;
}
}