C++ 學習筆記 Template Method Pattern
Tamplate Method Pattern
模板方法模式:特點是把共有部分集中到基類中,不同部分分散到不同子類中去實現。C++ 對此還有一種特殊的設計 NVI 。
設計出發點:(1)提高程式碼複用性, 不同派生類的共同部分集中在基類中(2)基類通過對派生類的具體實現來拓展不同的功能。
生活中的例子:(1)炒菜,炒不同的菜,會有相同的步驟(倒油,熱油,裝盤等),也會有不同的步驟(加不同的材料,佐料等),在這一連串操作中,把不同的部分分到不同的派生類中實現(2)登入不同系統的過程,有相同的步驟(聯網,開啟瀏覽器,關閉瀏覽器),也有不同的步驟(輸入不同網址,不同登入方式等),這一連串操作也可以運用模板方法。
例子:登入不同系統
基類 : loginSystem
(1)將一連串操作的共同部分集中在一起,供派生類直接呼叫
(2)為派生類提供介面,實現各自不同的部分
// 基類, 登入某個系統 class loginSystem { public: virtual ~loginSystem() = default; // ... 特別處理 copy constructor, assignment oeprator, move constructor 等 void loginIn() { connect(); // 連線校園網 openBrowser(); // 開啟瀏覽器 inputAdress(); // 輸入網址 loginMethod(); // 登陸方式 closeBrowser(); // 關閉瀏覽器 } static void connect() { std::cout << "\n連線校園網\n"; } static void openBrowser() { std::cout << "\n開啟瀏覽器\n"; } virtual void inputAdress() = 0; // 介面 virtual void loginMethod() = 0; // 介面 static void closeBrowser() { std::cout << "\n關閉瀏覽器\n"; } } ;
派生類 1 : 登入支付寶
// 派生類, 登入支付寶 // 登入方式 : 手機驗證碼 class loginAlipay : public loginSystem { private: std::string phoneNumber = "1326176****"; std::string verifyCode = "**0219"; public: void inputAdress() override { std::cout << "\n輸入 https://www.alipay.com\n"; } void loginMethod() override { std::cout << "\n手機號 : "; std::cin >> phoneNumber; std::cout << "\n驗證碼 : "; std::cin >> verifyCode; } } ;
派生類 2 : 登入 QQ 郵箱
// 派生類, 登入 QQ 郵箱
// 登陸方式 : 使用者名稱密碼登入
class loginMail : public loginSystem {
private:
std::string userName = "Fluence";
std::string passWord = "YHL";
public:
void inputAdress() override {
std::cout << "\n輸入 https://mail.qq.com\n";
}
void loginMethod() override {
std::cout << "\n使用者名稱 : ";
std::cin >> userName;
std::cout << "\n密碼 : ";
std::cin >> passWord;
}
} ;
派生類 3: 登入銀行賬戶
// 派生類, 登入銀行
// 登陸方式: 指紋識別
class loginBank : public loginSystem {
private:
std::vector<double> fingerPrint;
public:
void inputAdress() override {
std::cout << "\n輸入 http://www.****.com/cn/index.html\n";
}
void loginMethod() override {
std::cout << "\n從本地採取指紋 : \n";
std::ifstream statistics("myFingerPrin.txt");
double details;
while(statistics >> details)
fingerPrint.emplace_back(details);
statistics.close(); // 為了簡略, 未加入 RAII, 非異常安全
}
} ;
測試程式碼:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <vector>
// ..... 以上 class
int main() {
using ptrType = std::shared_ptr<loginSystem>;
ptrType alier = std::make_shared<loginAlipay>();
std::cout << "\n\n--------------- 登入支付寶 ----------------\n";
alier->loginIn();
ptrType qqmailer = std::make_shared<loginMail>();
std::cout << "\n\n--------------- 登入 QQ 郵箱 ----------------\n";
qqmailer->loginIn();
ptrType banker = std::make_shared<loginBank>();
std::cout << "\n\n--------------- 登入銀行 ----------------\n";13261
banker->loginIn();
return 0;
}
執行結果:
--------------- 登入支付寶 ----------------
連線校園網
開啟瀏覽器
輸入 https://www.alipay.com
手機號 : 13261764268
驗證碼 : 920219
關閉瀏覽器
--------------- 登入 QQ 郵箱 ----------------
連線校園網
開啟瀏覽器
輸入 https://mail.qq.com
使用者名稱 : Fluence
密碼 : YHL
關閉瀏覽器
--------------- 登入銀行 ----------------
連線校園網
開啟瀏覽器
輸入 http://www.****.com/cn/index.html
從本地採取指紋 :
關閉瀏覽器
學習《Effective C++ 》的過程中看到了 NVI (non-virtual interface) 的概念,開啟了我對模板方法的好奇。個人以為,NVI 對於理解模板方法大有裨益。