设计模式:模板模式 CRTP设计习语

news2024/9/23 1:31:11

一、模板模式

1、模板模式

1)定义

定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override重写)该算法的某些特定步骤。

2)动机(motivation)

> 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。

> 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

结构化软件设计流程:

面向对象软件设计流程:

 

3)类图

 AbstractClass是抽象类,也是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法。

ConCreteClass,实现父类所定义的一个或多个抽象方法。每个AbstractClass都可以有任意多个ConCreteClass与之对应,而每一个ConCreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

4)代码实现

#include <iostream>
#include <string>
#include<memory>
using namespace std;

class Library
{
public:
	void run() //template method
	{
		step1();
		while (!step2()) //多态调用
			step3();
		step4(); //多态调用
		step5();
	}
	virtual ~Library() {}

protected:
	void step1()
	{
		cout << "Library.step1()" << endl;
	}

	void step3()
	{
		cout << "Library.step3()" << endl;
	}

	void step5()
	{
		cout << "Library.step5()" << endl;
	}

protected:
	int number{ 0 };

private: //NVI: Non-Virtual Interface
	virtual bool step2() = 0;
	virtual int step4() = 0;
};

class App : public Library
{
private:
	bool step2() override
	{
		//Library::step2();//静态绑定
		cout << "App.step2()" << endl;
		number++;
		return number >= 3;
	}

	int step4() override
	{
		cout << "App.step4() : " << number << endl;
		return number;
	}
};

int main()
{
	std::unique_ptr<Library> library = std::make_unique<App>();

	//1. 存储成本:虚表指针 + 虚表结构(共享)
	//2. 调用成本: 间接指针辨析, 无法inline
	library->run();

	system("pause");
	return 0;
}

5)要点总结

> Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。

> 除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。

> 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将他们设置为protected或private方法(公有接口非虚NVI,Non-Virtual Interface)。

二、CRTP习语

1、CRTP

1)定义

CRTP(Curious Recurring Template Pattern):奇异递归模板模式。通过将基类模板参数设置为子类,从而实现静态多态(静态接口),或者扩展接口(委托实现)。

2)要点

> class Sub:public Base<Sub>通过模板参数,将子类类型在编译时注入基类,从而实现在基类中提前获取子类类型信息。

> static_cast<T*>(this)将基类指针转型为模板子类T的指针。

> Base类型为不完整类型,不能使用Sub参与内存布局,但可以在函数内使用(发生调用,模板编译时辨析即可)。

> 删除对象,也要使用编译时多态进行删除,避免直接delete。

3)代码实现

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <vector>
using namespace std;

template <typename T>
class Library
{
public:
	void run() //template method
	{
		step1();
		while (!sub()->step2()) //子类调用
			step3();
		sub()->step4(); //子类调用
		step5();
	}

	void destroy()
	{
		delete sub();
	}
protected:
	T* sub() {
		return static_cast<T*>(this);
	}
	void step1()
	{
		cout << "Library.step1()" << endl;
	}

	void step3()
	{
		cout << "Library.step3()" << endl;
	}

	void step5()
	{
		cout << "Library.step5()" << endl;
	}
protected:
	int number{ 0 };

	bool step2() { return false; }
	int step4() { return 0; }
public:
	~Library() {
		cout << "Library dtor" << endl;
	}
};

class App : public Library<App>
{
public:
	bool step2()
	{
		cout << "App.step2()" << endl;
		number++;
		return number >= 3;
	}
	int step4()
	{
		cout << "App.step4() : " << number << endl;
		return number;
	}

	~App() {
		cout << "App dtor" << endl;
	}
};

template<typename T>
void invoke(Library<T> &lib)
{
	lib.run();
}

int main()
{
	{
		Library<App> *pLib = new App();
		pLib->run();
		pLib->destroy();
		cout << endl;
	}

	cout << "----------------------------" << endl;
	{
		auto lambda = [](auto p) { p->destroy(); };
		unique_ptr<Library<App>, decltype(lambda)> uptr(new App(), lambda);
		uptr->run();
	}
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tensorflow 学习笔记(二):神经网络的优化过程

前言&#xff1a; 学习跟随 如何原谅奋力过但无声的 tensorflow 笔记笔记。 本章主要讲解神经网络的优化过程&#xff1a;神经网络的优化方法&#xff0c;掌握学习率、激活函数、损失函数和正则化的使用&#xff0c;用 Python 语言写出 SGD、Momentum、Adagrad、RMSProp、Ada…

2023-02-18干活记录

MathBERT: 耗时&#xff1a;2-3hours(昨天和人聊天聊完了&#xff0c;今天九点才到实验室&#xff0c;呜呜呜一早上就看了个论文) 读论文&#xff1a;BERT-Based Embedding Model for Formula Retrieval Corpus Description&#xff1a; resource:from MSE;the formulas ex…

腾讯云——负载均衡CLB

负载均衡 CLB 提供四层&#xff08;TCP 协议/UDP 协议/TCP SSL 协议&#xff09;和七层&#xff08;HTTP 协议/HTTPS 协议&#xff09;负载均衡。您可以通过 CLB 将业务流量分发到多个后端服务器上&#xff0c;消除单点故障并保障业务可用性。CLB 自身采用集群部署&#xff0c;…

电子技术——共栅和共源共栅放大器的高频响应

电子技术——共栅和共源共栅放大器的高频响应 我们在之前学过无论是是CS放大器还是CE放大器&#xff0c;都可以看做是一个带通&#xff08;IC低通&#xff09;滤波器。在高频处的响应收到输入电容 CinC_{in}Cin​ 的限制&#xff08;主要是米勒效应&#xff09;。因此&#xff…

中南民族大学数字电路实验一

数字电路实验一基本逻辑门实验1.与非门实现与门2.与非门实现或门3.与非门实现或非门4.与非门实现异或门5.与非门实现与或门6.与非门实现与或非门实验报告结果分析基本逻辑门实验 一、实验目的 1&#xff0e;掌握 logisim 软件的使用方法&#xff1b; 2&#xff0e;学习基于该软…

基于蜣螂算法优化Kmeans图像分割-附代码

基于蜣螂优化Kmeans图像分割算法 - 附代码 文章目录基于蜣螂优化Kmeans图像分割算法 - 附代码1.Kmeans原理2.基于蜣螂算法的Kmeans聚类3.算法实验结果4.Matlab代码摘要&#xff1a;基于蜣螂优化Kmeans图像分割算法。1.Kmeans原理 K-Means算法是一种无监督分类算法&#xff0c;…

蚂蚁感冒---第五届蓝桥杯真题

目录 题目链接 题目描述 分析&#xff1a; 代码&#xff1a; y总综合​ 666 题目链接 1211. 蚂蚁感冒 - AcWing题库 题目描述 分析&#xff1a; y总真牛逼&#xff0c;掉头等价于穿过&#xff0c;以第一个点为分界点&#xff0c;分别判断 代码&#xff1a; &#xff08;自…

Java线程池的创建以及原理

一、为什么要使用线程池 在外面的日常开发中&#xff0c;也使用了不少池化技术&#xff0c;比如线程池、数据库连接池、HTTP连接池等等都是对这个思想的应用。 池化技术的思想主要是为了减少每次获取资源的消耗&#xff0c;提高对资源的利用率。 线程池提供了一种限制和管理资…

centos7系统-kubeadm安装k8s集群(v1.26版本)亲测有效,解决各种坑可供参考

文章目录硬件要求可省略的步骤配置虚拟机ip设置阿里镜像源各服务器初始化配置配置主节点的主机名称配置从节点的主机名称配置各节点的Host文件关闭各节点的防火墙关闭selinux永久禁用各节点的交换分区同步各节点的时间将桥接的IPv4流量传递到iptables的链&#xff08;三台都执行…

PHP面向对象01:面向对象基础

PHP面向对象01&#xff1a;面向对象基础一、关键字说明二、技术实现1. 定义类2. 类成员三、 访问修饰限定符1. public2. protected3. private4. 空修饰限定符四、类内部对象五、构造和析构1. 构造方法2. 析构方法六、范围解析操作符1. 访问类常量2. 静态成员3. self关键字七、类…

自动驾驶:时钟同步

文章目录 一、自动驾驶时间同步简介二、时间同步需要的服务1、PTP1.1 ptp4l三、UTC转换UNIX时间戳(timestamp)一、自动驾驶时间同步简介 二、时间同步需要的服务 1、PTP ptp4l -i mgbe3_0 -f /etc/automotive-slave.cfg & phc2sys -s mgbe3_0 -O 0

IDEA插件 RestfulTool插件——Restful服务开发辅助工具集

IDEA插件 RestfulTool插件——Restful服务开发辅助工具集 目录IDEA插件 RestfulTool插件——Restful服务开发辅助工具集1.插件介绍2.安装方式3.使用方法1.插件介绍 RestfulTool插件。一套 Restful 服务开发辅助工具集&#xff1a; 提供了一个 Services tree 的显示窗口 双击 …

Linux C/C++ 多线程TCP/UDP服务器 (监控系统状态)

Linux环境中实现并发TCP/IP服务器。多线程在解决方案中提供了并发性。由于并发性&#xff0c;它允许多个客户端同时连接到服务器并与服务器交互。 Linux多线程编程概述 许多应用程序同时处理多项杂务。服务器应用程序处理并发客户端&#xff1b;交互式应用程序通常在处理后台…

80211无线网络架构

无线网络架构物理组件BSS&#xff08;Basic Service Set&#xff09;基本服务集BSSID&#xff08;BSS Identification&#xff09;ssid&#xff08;Service Set Identification&#xff09;ESS&#xff08;Extended Service Set&#xff09;扩展服务集物理组件 无线网络包含四…

【C++学习】基础语法(三)

众所周知C语言是面向过程的编程语言&#xff0c;关注的是过程&#xff1b;解决问题前&#xff0c;需要分析求解的步骤&#xff0c;然后编辑函数逐步解决问题。C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事拆分成不同的对象&#xff0c;不同对象间交互解决问…

C++:类与对象

文章目录一.面向过程和面向对象的初步认识二.类1.类的初步认识2.类的定义3.类的访问限定符4.类的作用域5.类的实例化6.类对象模型三.this指针1.什么是this指针2.this指针的特性3.this指针的空指针问题四.浅谈封装五.类的默认成员函数1.构造函数1.1构造函数的概念1.2构造函数的用…

jenkins 安装 -适用于在线安装 后续写个离线安装的

jenkins安装1.下载jenkins2.安装启动3.附件卸载jdk的命令4.配置jenkins一、在jenkins配置文件中配置jdk环境变量二、修改jenkins默认的操作用户1.下载jenkins jenkins官网下载 https://www.jenkins.io/ 点击下载 我是centos系统所以选择centos&#xff0c;点击后按着官方提供…

golang简单实现chatgpt网页聊天

效果如图&#xff1a; 安装openai的sdk&#xff1a; go get github.com/sashabaranov/go-gpt3go代码&#xff1a; main.go package mainimport ("fmt""net/http""os"gogpt "github.com/sashabaranov/go-gpt3" )var client gogpt.N…

高可用 - 02 Keepalived_VRRP工作原理

文章目录Keepalived VS HeartbeatKeepalived的用途VRRP与工作原理物理路由器和虚拟路由器Keepalived VS Heartbeat Keepalived是Linux下一个轻量级的高可用解决方案&#xff0c;它与Heartbeat、RoseHA实现的功能类似&#xff0c;都可以实现服务或者网络的高可用&#xff0c;但…

SmS-Activate一款好用的短信验证码接收工具

前言 有些国外应用在使用应用上的功能时需要注册账号&#xff0c;由于某种不可抗因素&#xff0c;我们的手机号一般不支持注册&#xff0c;接收不到信息验证码&#xff0c;于是我们可以使用SmS-Activate提供的服务&#xff0c;使用$实现我们的需求&#xff08;大概一次验证1-5…