C++ 学习笔记(20) Template Method Pattern

版权声明:如若转载,注明出处即可 https://blog.csdn.net/nishisiyuetian/article/details/82753689

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 对于理解模板方法大有裨益。

猜你喜欢

转载自blog.csdn.net/nishisiyuetian/article/details/82753689