当前位置: 首页 > news >正文

设计模式 19 模板模式 Template Pattern

设计模式 19 模板模式 Template Pattern

1.定义

        模板模式(Template Pattern)是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的具体实现延迟到子类中。在模板模式中,定义了一个抽象类,其中包含了一个模板方法(template method),这个方法定义了算法的基本结构和步骤,但其中的具体步骤由子类来实现。

        模板模式主要用于在不同子类中封装通用的行为,同时保持整体算法结构的一致性。通过模板方法模式,使得父类能够控制方法的执行顺序,同时细节延迟到子类实现。

2.内涵

模板模式包含以下几个角色:

  1. Abstract Class(抽象类):定义了一个模板方法,该方法是算法的骨架,其中调用了一系列抽象或具体的步骤。抽象类可能还包含了一些通用的实现,这些实现可以在模板方法中直接调用,也可以在需要时在子类中覆盖。
  2. Concrete Class(具体类):继承自抽象类,并实现了其中的具体步骤。每个具体类可以根据需要实现抽象类中定义的方法,并将其组合在一起形成完整的算法。

通过模板模式,可以实现代码复用、减少重复代码的编写,同时保持算法的统一性和一致性。模板模式能够提供一个稳定的算法框架,同时允许子类自由扩展或修改算法的某些部分。

=======================
|      AbstractClass   |
|----------------------|
|+ templateMethod()   |  
|+ primitiveOperation1()|
|+ primitiveOperation2()|
=======================||||=====================|    ConcreteClassA   ||----------------------||# primitiveOperation1()||# primitiveOperation2()|=====================||||=====================|   ConcreteClassB    ||----------------------||# primitiveOperation1()||# primitiveOperation2()|=====================


     
AbstractClass(抽象类):这是模板模式的核心部分,抽象类定义了模板方法 templateMethod() 和两个抽象方法 primitiveOperation1() 和 primitiveOperation2(),其中 templateMethod() 指定了算法的框架,包括一系列调用步骤,而 primitiveOperation1() 和 primitiveOperation2() 则是需要在具体子类中实现的具体步骤。

ConcreteClassA 和 ConcreteClassB(具体类):这是实际实现模板模式的具体子类。它们继承了 AbstractClass 并实现了其中的抽象方法 primitiveOperation1() 和 primitiveOperation2()。每个具体类可能实现完全不同的具体步骤,但是它们遵循相同的模板方法结构(templateMethod())。

     
     
3.使用示例

/*** The Abstract Class defines a template method */
class AbstractClass {/*** The template method defines the skeleton of an algorithm.*/public:void TemplateMethod() const {this->BaseOperation1();this->RequiredOperations1();this->BaseOperation2();this->Hook1();this->RequiredOperation2();this->BaseOperation3();this->Hook2();}protected:void BaseOperation1() const {std::cout << "AbstractClass says: I am doing the bulk of the work\n";}void BaseOperation2() const {std::cout << "AbstractClass says: But I let subclasses override some operations\n";}void BaseOperation3() const {std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n";}virtual void RequiredOperations1() const = 0;virtual void RequiredOperation2() const = 0;virtual void Hook1() const {}virtual void Hook2() const {}
};/*** Concrete classes have to implement all abstract operations of the base class.* They can also override some operations with a default implementation.*/
class ConcreteClass1 : public AbstractClass {protected:void RequiredOperations1() const override {std::cout << "ConcreteClass1 says: Implemented Operation1\n";}void RequiredOperation2() const override {std::cout << "ConcreteClass1 says: Implemented Operation2\n";}
};class ConcreteClass2 : public AbstractClass {protected:void RequiredOperations1() const override {std::cout << "ConcreteClass2 says: Implemented Operation1\n";}void RequiredOperation2() const override {std::cout << "ConcreteClass2 says: Implemented Operation2\n";}void Hook1() const override {std::cout << "ConcreteClass2 says: Overridden Hook1\n";}
};void ClientCode(AbstractClass *class_) {// ...class_->TemplateMethod();// ...
}int main() {std::cout << "Same client code can work with different subclasses:\n";ConcreteClass1 *concreteClass1 = new ConcreteClass1;ClientCode(concreteClass1);std::cout << "\n";std::cout << "Same client code can work with different subclasses:\n";ConcreteClass2 *concreteClass2 = new ConcreteClass2;ClientCode(concreteClass2);delete concreteClass1;delete concreteClass2;return 0;
}


输出:

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anywaySame client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

上述代码类图


4.注意事项

在使用模板模式(Template Pattern)时,有一些注意事项需要注意以避免可能的问题和踩坑:

  • 抽象类的设计:在定义抽象类时,需要仔细考虑模板方法中的逻辑和步骤顺序,确保所有子类都能正确实现这些步骤。避免在抽象类中定义过多的具体实现,应保持抽象类的简洁性,只包含框架结构和必要的抽象方法。
  • 子类实现的一致性:子类在实现抽象方法时,需要保持接口一致性,确保方法签名和返回类型与父类中定义的一致。否则可能会导致编译错误或运行时异常。
  • 算法的扩展性:模板模式允许子类修改或扩展算法的某些部分,但注意避免过度扩展和修改,以免破坏算法的一致性和规范性。确保扩展的功能是相对独立且有必要的。
  • 模板方法的执行顺序:模板方法定义了算法的执行顺序,子类在实现具体步骤时要遵循这个顺序。任何不当的调整可能会导致算法步骤的混乱或错误。
  • 继承的关系:模板模式使用了继承机制,但应该避免过度使用继承导致类层次结构复杂。确保继承关系的合适性和合理性。
  • 钩子方法:在抽象类中可以定义钩子方法,用于控制算法的某些部分是否执行。需要谨慎设计和使用钩子方法,避免影响算法的整体结构和正确性。
  • 单一职责原则:确保每个具体类只负责实现自己的具体步骤,遵循单一职责原则,避免一个类承担过多的责任和功能。
5.最佳实践


在开发中实现模板模式(Template Pattern)时,可以采用以下一些比较好的经验:

  • 合理抽象和分离关注点:在设计抽象类时,需要将通用的算法步骤抽象出来,同时将具体步骤留给具体子类实现。这样可以实现算法的复用和解耦,同时方便后续的扩展和修改。
  • 使用钩子方法:钩子方法是一种可以控制算法流程的手段,可以在抽象类中定义一些空方法或默认实现,具体子类可以选择性地重写这些方法来影响算法的执行。这样可以在不改变模板方法结构的情况下灵活地扩展和定制算法。
  • 保持一致性:确保所有具体子类实现的具体步骤都是与抽象类中定义的一致的,保持算法的一致性和规范性,避免出现错误或混乱。
  • 封装变化部分:在设计模板模式时,将会变化的部分抽象出来,以便随时扩展和修改,而将不变的部分固定在模板方法中,确保算法的稳定性和可维护性。
  • 使用工厂方法:在具体类的实例化时,可以考虑使用工厂方法模式(Factory Method Pattern),将实例化过程放在具体的工厂类中,以便灵活地切换不同的具体子类。

6.总结

通过模板模式,可以实现代码复用、减少重复代码的编写,同时保持算法的统一性和一致性。模板模式能够提供一个稳定的算法框架,同时允许子类自由扩展或修改算法的某些部分。


 

相关文章:

设计模式 19 模板模式 Template Pattern

设计模式 19 模板模式 Template Pattern 1.定义 模板模式&#xff08;Template Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤的具体实现延迟到子类中。在模板模式中&#xff0c;定义了一个抽象类&#xff0c;其中包含了一个…...

PHP如何实现实时计算使用者消耗服务器资源费用?

最近几天遇到一个客户,提出一个很有意思的东西!当然客户的项目方案这里不方便说,这里就假定客户的项目是腾讯云?哈哈哈哈哈 以前客户的收费方案是按月、按季度、按年收费,现在半路杀出了很多程咬金,导致之前的收费方案有点儿贵,没啥性价比,那就搞一个看起来很“便宜”…...

在C++中自定义命名空间,在命名空间中定义string变量,同时定义一个函数实现单词逆置

代码 #include <iostream> #include <cstring> using namespace std; namespace my_space {string s;void reverse(string s);//定义逆置函数 } using namespace my_space; void my_space::reverse(string s){int lens.size();int i0;int jlen-1;while(i<j){//…...

【leetcode 141】环形链表——快慢指针(龟兔赛跑)

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…...

容器(Container)的详细介绍

容器&#xff0c;作为现代软件开发和部署的核心技术之一&#xff0c;已经成为云计算、微服务架构等领域的基石。容器技术通过提供轻量级的虚拟化环境&#xff0c;实现了应用程序的快速部署、迁移和扩展&#xff0c;极大地提高了软件开发的效率和灵活性。本文将详细介绍容器的概…...

Python 网格变换之平移、旋转、缩放、变换矩阵

网格变换 一、平移1.1、代码示例1.2、结果示例二、旋转2.1、代码示例2.2、结果示例三、缩放3.1、代码示例3.2、结果示例四、变换矩阵4.1、代码示例4.2、结果示例一、平移 网格平移:将网格沿着特定的方向移动一段距离。 1.1、代码示例...

推荐10款优秀的组件库(一)

1.Ant Desgin UI 网址&#xff1a; https://ant-design-mobile.antgroup.com/zh Ant Design - 一套企业级 UI 设计语言和 React 组件库 "Ant Design Mobile"是一个在线的移动端Web体验平台&#xff0c;让你探索移动端Web的体验极限。 添加图片注释&#xff0c;不…...

freertos的信号量和互斥锁学习笔记

freertos的信号量和互斥锁有两个比较形象的例子可以解释两者的主要用途。 第一个是信号量&#xff1a; 使用信号量的最初目的是为了给共享 资源建立一个标志&#xff0c;该标志表示该共享资源被占用情况。这样&#xff0c;当一个任务在访问共享资源之前&#xff0c;可以先对这…...

C++基础——vector的详解与运用

vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改变的&#xff0c;…...

const指针,星号判断方法

一 示例代码 1. const char *p // 指向常量的指针 2. char const *p // 指向常量的指针 3. char * const p // 指针常量二 判断方法 const在星号左边&#xff0c;指向常量的指针&#xff0c;指针p可修改。 const在星号右边&#xff0c;指针常量&#xff0c;指针p不可修改。...

移动摄像头专网需要解vlan,如何解决

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…...

5.27周报

这两周邻近毕业故没有很多时间来学习课余内容&#xff0c;另外最近身体有些不舒服【偏头痛】&#xff0c;所以学的内容不多&#xff0c;包括SVM向量机和ResNet【不包括代码复现】 1.SVM支持向量机的大概内容 1、目的&#xff1a; 主要内容是如何找到分类的那条线【超平面】—…...

C-数据结构-树状存储的基本实现

/* 理解和记忆递归的关键在于把握递归的本质和函数调用的过程。递归函数在每次调用时会把当前状态压入调用栈&#xff0c;直到满足终止条件后开始回溯。理解基准条件和递归步骤&#xff1a;每个递归函数都需要有基准条件&#xff08;如节点为空时返回&#xff09;&#xff0c;并…...

指纹识别经典图书、开源算法库、开源数据库

目录 1. 指纹识别书籍 1.1《精通Visual C指纹模式识别系统算法及实现》 1.2《Handbook of Fingerprint Recognition》 2. 指纹识别开源算法库 2.1 Hands on Fingerprint Recognition with OpenCV and Python 2.2 NIST Biometric Image Software (NBIS) 3. 指纹识别开源数…...

嵌入式之译码器

系列文章目录 译码器嵌入式之译码器 嵌入式之译码器 系列文章目录一、译码器定义二、常见类型的译码器三、工作原理 一、译码器定义 译码器&#xff08;Decoder&#xff09;是一种数字电路&#xff0c;其主要功能是从输入的编码信号中解码出特定的信息或控制信号。 译码器通常…...

分成sum接近的2个集合,返回相对小的sum

题目描述&#xff1a;给定一个正数数组arr&#xff0c;请把arr中所有的数分成两个集合&#xff0c;尽量让两个集合的累加和接近&#xff0c;返回最接近的情况下&#xff0c;较小集合的累加和sum。 way&#xff1a;选还是不选 //arr[index...]可以自由选择,返回累加和尽量接近…...

SpringBoot前置知识01-SPI接口

SpringBoot前置知识-SPI接口 介绍 Java中SPI是一种服务发现机制&#xff0c;或者说是一种思想&#xff0c;亦是一种约定。其实JDK中的JDBC就是使用了这种用思想&#xff0c;JDBC在JDK中只定义了接口&#xff0c;并没有实现类&#xff0c;连接什么数据库就要引入什么数据库的驱…...

数学建模--LaTeX的基本使用

目录 1.回顾 2.设置这个页眉和页脚 3.对于字体的相关设置 4.对于这个分级标题的设置 5.列表的使用 6.插入图片 1.回顾 &#xff08;1&#xff09;昨天我们了解到了这个latex的使用基本常识&#xff0c;以及这个宏包的概念&#xff0c;区域的划分&#xff0c;不同的代码代…...

授权调用: 介绍 Transformers 智能体 2.0

简要概述 我们推出了 Transformers 智能体 2.0&#xff01; ⇒ &#x1f381; 在现有智能体类型的基础上&#xff0c;我们新增了两种能够 根据历史观察解决复杂任务的智能体。 ⇒ &#x1f4a1; 我们致力于让代码 清晰、模块化&#xff0c;并确保最终提示和工具等通用属性透明化…...

流媒体内网穿透/组网/视频协议转换EasyNTS上云网关如何更改密码?

EasyNTS上云网关的主要作用是解决异地视频共享/组网/上云的需求&#xff0c;网页对域名进行添加映射时&#xff0c;添加成功后会生成一个外网访问地址&#xff0c;在浏览器中输入外网访问地址&#xff0c;即可查看内网应用。无需开放端口&#xff0c;EasyNTS上云网关平台会向Ea…...

Supermask:冻结权重+二值掩码的神经网络子结构发现方法

1. 什么是 Supermasks&#xff1f;——不是“超级面具”&#xff0c;而是神经网络里的“先天直觉” 你有没有试过教一个刚学会走路的孩子认苹果&#xff1f;你不需要从零开始教他光谱分析、细胞结构或者植物分类学&#xff0c;只要拿个红彤彤的苹果在他眼前晃一晃&#xff0c;再…...

如何用Autolabel在5分钟内完成数据标注:面向新手的终极实战指南

如何用Autolabel在5分钟内完成数据标注&#xff1a;面向新手的终极实战指南 【免费下载链接】autolabel Label, clean and enrich text datasets with LLMs. 项目地址: https://gitcode.com/gh_mirrors/au/autolabel 还在为数据标注发愁吗&#xff1f;&#x1f914; 传统…...

主产区安全整改深化 行业加速洗牌(5 月 21 日)

1.湖南浏阳等产区开展全覆盖排查&#xff0c;重点整治违规库存、超量存放、追溯缺失等问题。 2.中小零售点面临搬迁 / 关停&#xff0c;合规化与信息化追溯成生存门槛。 3.海外市场&#xff1a;美国堪萨斯城皇家队赛事烟花秀&#xff08;5 月 22 日&#xff09;&#xff0c;赛事…...

ElevenLabs支持贵州话吗?2024最新实测结果+3种绕过官方限制的合规接入方案

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;ElevenLabs对贵州话的原生支持现状与底层语音技术解析 ElevenLabs当前官方模型库中尚未提供针对贵州话&#xff08;含贵阳话、遵义话等主要方言变体&#xff09;的独立语言选项或预训练语音模型。其公开支持的…...

给硬件新人的半导体测试扫盲:从晶圆到芯片,CP/FT/BI测试到底在测什么?

半导体测试全流程解析&#xff1a;从晶圆到芯片的质量守护 走进半导体制造的世界&#xff0c;就像观察一座精密运转的钟表工厂——每个齿轮都必须完美咬合才能确保最终产品走时准确。对于刚接触这个领域的新人来说&#xff0c;理解芯片从硅片到成品的测试流程&#xff0c;是掌握…...

从Arduino按键消抖到ESP32低功耗唤醒:细说电容充放电在嵌入式里的那些实用门道

从Arduino按键消抖到ESP32低功耗唤醒&#xff1a;细说电容充放电在嵌入式里的那些实用门道 在嵌入式开发中&#xff0c;电容充放电原理的应用远比教科书上的公式计算更加丰富多彩。从最简单的按键消抖到复杂的低功耗系统设计&#xff0c;合理利用RC特性往往能以极低成本解决实际…...

精细化管控API调用,Taotoken的访问控制与审计日志功能详解

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 精细化管控API调用&#xff0c;Taotoken的访问控制与审计日志功能详解 当企业或团队将大模型能力集成到自身业务中时&#xff0c;除…...

红黑树(简易版)

一、一句话红黑树 ≈ 近似平衡的二叉查找树&#xff0c;保证查找 O(log n)二、5 条性质&#xff08;背前 4 条即可&#xff09; 节点是 红 / 黑根是 黑叶子&#xff08;NIL&#xff09;是 黑红节点的孩子必须是黑&#xff08;不能连续红&#xff09;任意节点到叶子的 黑高相同&…...

AI-auth-toolkit社区贡献指南:从入门到核心开发者

AI-auth-toolkit社区贡献指南&#xff1a;从入门到核心开发者 【免费下载链接】genai-compliance-bench GenAI compliance benchmark is a evaluation benchmarks for generative AI in regulated industries. 项目地址: https://gitcode.com/gh_mirrors/ai/genai-compliance…...

如何快速掌握GetQzonehistory:QQ空间备份的完整教程

如何快速掌握GetQzonehistory&#xff1a;QQ空间备份的完整教程 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否担心多年积累的QQ空间说说会随着时间流逝而消失&#xff1f;那些记…...