实战设计模式之模板方法模式

概述

        模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类为这些步骤提供具体的实现。模板方法模式非常适合用于那些有固定流程或步骤,但在不同情况下需要稍微调整或扩展每个步骤的场景。

        咖啡制作是现实生活中运用模板方法模式的一个典型例子:虽然不同种类的咖啡(比如:浓缩咖啡、拿铁、卡布奇诺等)有不同的制作细节,但它们共享一个通用的流程框架。这个框架包括一些基本步骤,比如:加热水、冲泡咖啡、倒入杯中、添加调料。通过使用模板方法模式,我们可以定义这个通用的流程,并允许具体的咖啡类型自定义某些步骤。

基本原理

        模板方法模式的基本原理是:通过一个抽象类来定义一个操作中算法的骨架(即一系列步骤),但将一些步骤的具体实现延迟到子类中。这样,子类可以通过重写这些步骤的方法来定制特定于该子类的行为,同时保持算法的整体流程不变。

        模板方法模式主要由以下三个核心组件构成。

        1、抽象类。定义了模板方法,该方法给出了算法的骨架,通常包含了一系列调用“原始操作”的方法。另外,抽象类还可能提供了一些默认实现的方法。

        2、原始操作。这些是在抽象类中声明的抽象方法,它们代表了算法的不同步骤,需要由具体的子类提供实现。

        3、具体类。继承自抽象类,并提供了抽象方法的具体实现。这允许不同的具体类根据自己的需求,对算法的部分步骤进行定制。

        基于上面的核心组件,模板方法模式的实现主要有以下四个步骤。

        1、创建抽象类。定义一个抽象类,在其中声明一个或多个模板方法。模板方法是一个具体方法,它定义了算法的框架,并调用了若干个抽象方法或其他基本操作。在抽象类中声明所有需要子类实现的抽象方法,

        2、定义抽象方法。确定哪些步骤需要子类提供具体实现,并在抽象类中将其声明为抽象方法。这些抽象方法,即原始操作,代表了算法的不同步骤。

        3、提供默认实现。如果某些步骤对于所有子类来说都是相同的,或者可以有一个合理的默认实现,则可以在抽象类中提供这些步骤的默认实现。子类可以根据需要,选择是否覆盖这些方法。

        4、创建具体类。创建具体类,继承自抽象类,并实现所有必要的抽象方法。

实战代码

        在下面的实战代码中,我们使用模板方法模式模拟了咖啡制作的过程。

        首先,我们定义了一个抽象类CCoffee,它包含了制作咖啡的算法骨架MakeCoffee。该方法依次调用了四个步骤:加热水(BoilWater)、冲泡咖啡粉(BrewCoffeeGrinds)、倒入杯中(PourInCup)、添加调料(AddCondiments)。在这四个步骤中,冲泡咖啡粉BrewCoffeeGrinds和添加调料AddCondiments被声明为纯虚函数,要求由具体的子类提供实现,而BoilWater和PourInCup提供了默认实现。

        接下来,我们定义了具体类CEspresso和CLatte。它们分别实现了浓缩咖啡和拿铁咖啡特有的冲泡和添加调料的方法,从而定制了各自的制作流程。

        最后,在main函数中,通过基类指针创建了CEspresso和CLatte对象,并调用了它们的MakeCoffee方法。

#include <iostream>
#include <string>using namespace std;// 抽象类,定义了制作咖啡的基本步骤
class CCoffee
{
public:// 模板方法,定义了制作咖啡的算法骨架void MakeCoffee(){BoilWater();BrewCoffeeGrinds();PourInCup();AddCondiments();}protected:// 基本步骤,由子类实现具体逻辑virtual void BrewCoffeeGrinds() = 0;virtual void AddCondiments() = 0;// 默认实现,可以被子类覆盖virtual void BoilWater(){cout << "Boiling water" << endl;}virtual void PourInCup(){cout << "Pouring into cup" << endl;}
};// 具体类:浓缩咖啡
class CEspresso : public CCoffee
{
protected:void BrewCoffeeGrinds() override{cout << "Dripping coffee through filter for espresso" << endl;}void AddCondiments() override{cout << "No condiments for espresso" << endl;}
};// 具体类:拿铁咖啡
class CLatte : public CCoffee
{
protected:void BrewCoffeeGrinds() override{cout << "Steeping coffee for latte" << endl;}void AddCondiments() override{cout << "Adding steamed milk and cinnamon" << endl;}
};int main()
{CCoffee* pEspresso = new CEspresso();pEspresso->MakeCoffee();cout << endl;CCoffee* pLatte = new CLatte();pLatte->MakeCoffee();delete pEspresso;delete pLatte;return 0;
}

总结

        模板方法模式通过将通用的算法框架放在抽象类中,使得这些通用步骤可以在所有子类之间共享。这减少了重复代码,并促进了代码复用。由于算法的整体结构由抽象类控制,确保了所有具体实现都遵循相同的流程。这样可以保证行为的一致性,尤其是在需要严格遵守某种操作顺序的情况下。虽然算法的整体结构是固定的,但允许子类重写某些步骤以满足特定需求,提供了极大的灵活性。

        虽然子类可以重写某些步骤,但它们不能改变算法的基本结构或顺序。这意味着,如果需要完全不同的算法流程,则无法仅通过重写现有方法来实现,必须重新设计整个结构。另外,对于简单的应用场景,引入模板方法模式可能会使设计变得过于复杂。特别是当只有少数几个步骤需要定制化时,使用这种模式可能显得过度设计。

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

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

相关文章

ROS1: 使用rosbag的方式将点云topic保存为pcd文件

ROS1: 使用rosbag的方式将点云topic保存为pcd文件。 分为两步&#xff1a;步骤1&#xff1a;通过rosbag录制点云 &#xff0c;步骤2&#xff1a;通过ros1将rosbag保存为点云pcd文件。 ------------------------ 步骤一&#xff1a;指令示例如下&#xff1a; # topic 名称&a…

MySQL 高级学习篇

一、连结&#xff08;Join&#xff09; 1.1 概念 联结&#xff08;Join&#xff09;操作用于将多个表中的列组合在一起&#xff0c;形成一个新的查询结果集。它允许我们从多个表中提取数据&#xff0c;并基于表之间的关系进行查询。 1.2 类型 1. 内联结&#xff08;INNER J…

clickhouse 学习总结

在 ClickHouse 中&#xff0c;配置文件通常位于 /etc/clickhouse 目录下。这个目录包含了多个配置文件&#xff0c;用于控制 ClickHouse 的各种服务&#xff08;如服务器、用户、远程服务等&#xff09;的配置。 数据存储目录/var/lib/clickhouse 配置 文件目录 /etc/clickho…

理解JavaScript中map和parseInt的陷阱:一个常见的面试题解析

前言 在JavaScript面试中&#xff0c;map和parseInt的组合常常被用作考察候选人对这两个方法理解深度的题目。让我们通过一个简单的例子来深入探讨其中的原理。 问题现象 [1, 2, 3].map(parseInt) // 输出结果是什么&#xff1f;很多人可能会预期输出[1, 2, 3]&#xff0c;但…

字符串 金额转换

package heima.Test09;import java.util.Scanner;public class Money {public static void main(String[] args) {//1。键盘录入一个金额Scanner sc new Scanner(System.in);//请输入一个数据String result "";int money;while (true) {System.out.println("请…

静态相机中的 CCD和CMOS的区别

文章目录 CCD处理方式CMOS处理方式两者区别 首先根据 成像原理&#xff0c;CCD和CMOS的作用是一致的&#xff0c;都是为了将光子转化为数字图像&#xff0c;只是 转换的方式出现差异。 CCD处理方式 获取光子&#xff1a; 在电荷耦合器件&#xff08;CCD&#xff09;传感器中…

Pycharm的终端无法使用Anaconda命令行问题详细解决教程

很多初学者在Windows系统上安装了Anaconda后&#xff0c;在PyCharm终端中运行Conda命令时&#xff0c;会遇到以下错误&#xff1a; conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保…

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…

TDengine 替换 Hadoop,彻底解决数据丢失问题 !

完全替换 Hadoop&#xff0c;彻底解决写入丢数问题 &#xff01;TDengine 助力积成电子更好服务电力客户&#xff01; 小T导读&#xff1a;在内蒙古某新能源集控项目中&#xff0c;三区需接入并分析大量风电、光伏逆变器及储能设备的监测数据。随着数据规模不断扩大&#xff0c…

从0到1认识ElasticStack

一、ES集群部署 操作系统Ubuntu22.04LTS/主机名IP地址主机配置elk9110.0.0.91/244Core8GB100GB磁盘elk9210.0.0.92/244Core8GB100GB磁盘elk9310.0.0.93/244Core8GB100GB磁盘 1. 什么是ElasticStack? # 官网 https://www.elastic.co/ ElasticStack早期名称为elk。 elk分别…

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…

DFT测试之TAP/SIB/TDR

TAP的作用 tap全称是test access port&#xff0c;是将jtag接口转为reset、sel、ce、ue、se、si、tck和so这一系列测试组件接口的模块。 jtag的接口主要是下面几个信号&#xff1a; 信号名称信号方向信号描述TCK&#xff08;测试时钟&#xff09;输入测试时钟&#xff0c;同…

Python对接印度股票数据源实战指南

Python对接印度股票数据源实战指南 基于StockTV API实现印度证券市场数据对接&#xff0c;覆盖实时行情、K线、指数等核心功能&#xff0c;提供完整开发方案与避坑指南 一、数据源选型要点&#xff08;技术维度对比&#xff09; 根据2025年最新实测数据&#xff0c;印度市场主…

usbutils工具的使用帮助

作为嵌入式系统开发中的常用工具&#xff0c;usbutils 是一套用于管理和调试USB设备的Linux命令行工具集。以下是其核心功能和使用方法的详细说明&#xff1a; 1. 工具组成 核心命令&#xff1a; lsusb&#xff1a;列出所有连接的USB设备及详细信息&#xff08;默认安装&#…

k8s入门教程(集群部署、使用,镜像拉取失败网络问题排查)

文章目录 K8S基础创建centos虚拟机K3S部署配置k3s容器containerd镜像2025年4月测试可用镜像源配置 Pod容器Deployment&#xff08;部署&#xff09;和ReplicaSet&#xff08;副本集&#xff09;镜像拉取失败问题排查 Service服务ServiceType取值 NameSpace命名空间声明式对象配…

使用VuePress2.X构建个人知识博客,并且用个人域名部署到GitHub Pages中

使用VuePress2.X构建个人知识博客&#xff0c;并且用个人域名部署到GitHub Pages中 什么是VuePress VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown 来书写内容&#xff08;如文档、博客等&#xff09;&#xff0c;然后 VuePress 会帮助你生成一个…

Vue3 + Element Plus 防止按钮重复点击的解决方案

在 Vue3 和 Element Plus 项目中&#xff0c;防止按钮重复点击是一个常见的需求&#xff0c;特别是在表单提交、支付等场景下。以下是几种实现方式&#xff1a; 1. 使用 Element Plus 的 loading 状态 Element Plus 的按钮组件本身就支持 loading 状态&#xff0c;这是最简单…

ES101系列09 | 运维、监控与性能优化

本篇文章主要讲解 ElasticSearch 中 DevOps 与性能优化的内容&#xff0c;包括集群部署最佳实践、容量规划、读写性能优化和缓存、熔断器等。 集群部署最佳实践 在生产环境中建议设置单一角色的节点。 Dedicated master eligible nodes&#xff1a;负责集群状态的管理。使用…

如何基于Mihomo Party http端口配置git与bash命令行代理

如何基于Mihomo Party http端口配置git与bash命令行代理 1. 确定Mihomo Party http端口配置 点击内核设置后即可查看 默认7892端口&#xff0c;开启允许局域网连接 2. 配置git代理 配置本机代理可以使用 127.0.0.1 配置局域网内其它机代理需要使用本机的非回环地址 IP&am…

SSL安全证书怎么安装?

SSI并非一个标准的、广为人知的安全证书类型&#xff0c;通常网站安装的是SSL/TLS证书&#xff0c;用于加密网站和用户浏览器之间的通信&#xff0c;保障数据传输安全。以下以安装SSL/TLS证书为例&#xff0c;介绍网站安装证书的步骤&#xff1a; 一、证书申请与获取 选择证书…