1. 程式人生 > >模板模式的應用之兩種登入控制(普通使用者和管理員)

模板模式的應用之兩種登入控制(普通使用者和管理員)

思考模板方法模式

(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 <iostream>
#include <string>

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;
	}
}