Python如何实现模板方法设计模式?什么是模板方法设计模式?Python 模板方法设计模式示例代码

什么是模板方法(Template Method)设计模式?

模板方法(Template Method)是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现。这种模式允许子类为一个算法的特定步骤提供实现,而不改变算法的结构。

在这里插入图片描述
在这里插入图片描述

模板方法模式通常包含两种类型的方法:

  1. 模板方法(Template Method): 定义了算法的骨架,提供了一个顶级的方法来定义算法的结构,这个方法通常是 final 或者不可被子类重写的。模板方法一般会调用一系列的抽象方法或者具体方法。

  2. 抽象方法(Abstract Method): 在模板方法中被声明但是没有实现,需要子类来实现具体的行为。

主要角色:

  1. 抽象类(Abstract Class): 包含模板方法和抽象方法定义算法的结构和步骤。

  2. 具体子类(Concrete Subclasses): 实现抽象类中的抽象方法,提供特定步骤的具体实现。

工作原理:

  1. 定义算法的骨架,包含一个模板方法。
  2. 模板方法定义了算法的步骤,其中某些步骤是抽象的,由子类实现。
  3. 子类提供特定步骤的实现,但整个算法的流程控制由模板方法负责。

python3 实现模板方法设计模式示例代码(一):

一个简单的示例是咖啡和茶的制备过程。制备咖啡和茶有相似的步骤(比如冲泡和加调味品),但是具体的饮料种类和调味品可能有所不同。在模板方法模式中,可以将冲泡和加调味品等步骤定义为模板方法,而具体的咖啡和茶则是子类,负责实现具体的冲泡方式和调味品。

这种模式允许在不改变算法结构的情况下,定制算法中的特定步骤。

以下是一个使用模板方法设计模式的 Python 示例,模拟了制备咖啡和茶的过程:

from abc import ABC, abstractmethod# 抽象类定义了模板方法
class Beverage(ABC):def prepare(self):self.boil_water()self.brew()self.pour_in_cup()if self.customer_wants_condiments():self.add_condiments()def boil_water(self):print("Boiling water")@abstractmethoddef brew(self):passdef pour_in_cup(self):print("Pouring into cup")@abstractmethoddef add_condiments(self):pass# 钩子方法def customer_wants_condiments(self):return True# 具体子类实现特定的步骤
class Coffee(Beverage):def brew(self):print("Dripping coffee through filter")def add_condiments(self):print("Adding sugar and milk")def customer_wants_condiments(self):response = input("Do you want to add sugar and milk? (y/n): ")return True if response.lower() == 'y' else Falseclass Tea(Beverage):def brew(self):print("Steeping the tea")def add_condiments(self):print("Adding lemon")def customer_wants_condiments(self):response = input("Do you want to add lemon? (y/n): ")return True if response.lower() == 'y' else False# 客户端代码
if __name__ == "__main__":print("Making coffee...")coffee = Coffee()coffee.prepare()print("\nMaking tea...")tea = Tea()tea.prepare()

在这个示例中,Beverage 是抽象类,定义了制备饮料的模板方法 prepare(),以及一些抽象方法(brew()add_condiments())。CoffeeTea 类是具体的子类,分别实现了咖啡和茶的具体制作步骤。通过模板方法 prepare(),它们调用了抽象方法完成了饮料的制作。其中 customer_wants_condiments() 是一个钩子方法,允许子类控制特定步骤的实现。

python3 实现模板方法设计模式示例代码(二):

当考虑更实际的场景时,模板方法模式可以应用在日志记录中。无论是将日志记录到文件、数据库或者控制台,都有相似的流程,但每种记录方式的具体步骤略有不同。

from abc import ABC, abstractmethodclass Logger(ABC):def log(self):self.connect()self.format_log()self.write_log()self.disconnect()@abstractmethoddef connect(self):pass@abstractmethoddef format_log(self):pass@abstractmethoddef write_log(self):pass@abstractmethoddef disconnect(self):passclass FileLogger(Logger):def connect(self):print("File Logger: Connecting to file...")def format_log(self):print("File Logger: Formatting log...")def write_log(self):print("File Logger: Writing log to file...")def disconnect(self):print("File Logger: Disconnecting from file...")class DatabaseLogger(Logger):def connect(self):print("Database Logger: Connecting to database...")def format_log(self):print("Database Logger: Formatting log...")def write_log(self):print("Database Logger: Writing log to database...")def disconnect(self):print("Database Logger: Disconnecting from database...")class ConsoleLogger(Logger):def connect(self):print("Console Logger: Connecting to console...")def format_log(self):print("Console Logger: Formatting log...")def write_log(self):print("Console Logger: Displaying log on console...")def disconnect(self):print("Console Logger: Disconnecting from console...")if __name__ == "__main__":file_logger = FileLogger()file_logger.log()print("\n")db_logger = DatabaseLogger()db_logger.log()print("\n")console_logger = ConsoleLogger()console_logger.log()

这个示例展示了不同类型的日志记录器(文件记录、数据库记录、控制台输出)共享相同的记录流程,但具体的记录方式各不相同。Logger 类定义了模板方法 log(),而各种记录器类实现了该方法的抽象步骤。这样,无论是文件记录、数据库记录还是控制台输出,都能使用相同的模板方法进行记录。


使用模板方法设计模式时,需要注意哪些地方?

在使用模板方法设计模式时,需要注意以下几个方面:

  1. 定义模板方法: 确保模板方法中包含算法的骨架,定义了整个算法的流程和顺序。模板方法应该是 final 或者不可被子类重写,以确保算法的稳定性。

  2. 区分抽象和具体方法: 确保正确地区分抽象方法和具体方法。抽象方法应该由子类来实现,而具体方法可以在抽象类中提供默认实现。

  3. 保持一致性和稳定性: 模板方法模式旨在定义算法的骨架,并且尽可能提供稳定的算法结构。因此,在使用模板方法时,应该确保算法中的步骤是稳定和一致的。

  4. 钩子方法的使用: 如果需要在模板方法中控制特定步骤的实现,可以使用钩子方法(即具有默认实现的方法),允许子类控制或改变算法的部分步骤。

  5. 维护封装性: 确保在子类中不会直接访问或修改父类中的其他方法或属性,以保持对象的封装性。

  6. 避免滥用模板方法模式: 不要为了使用模板方法模式而人为地将一些不相关的操作强行放入模板方法中,这可能会导致类过于臃肿和难以维护。

  7. 适当的抽象级别: 考虑模板方法的抽象级别,要确保足够的抽象来适应各种子类的实现,但不要过度抽象导致子类难以实现。

总的来说,使用模板方法设计模式时,需要注意定义模板方法、合理使用抽象和具体方法、保持一致性和稳定性,以及保持良好的封装性。同时,要根据实际情况和需求适当地使用钩子方法,并避免滥用模板方法模式。


本文就到这里了,感谢您的阅读 。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 🍇

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

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

相关文章

【Flink】Process Function

目录 1、ProcessFunction解析 1.1 抽象方法.processElement() 1.2 非抽象方法.onTimer() 2、Flink中8个不同的处理函数 2.1 ProcessFunction 2.2 KeyedProcessFunction 2.3 ProcessWindowFunction 2.4 ProcessAllWindowFunction 2.5 CoProcessFunction 2.6 ProcessJo…

【Java系列】SpringBoot 集成MongoDB 详细介绍

目录 写在前面 一、步骤介绍 步骤 1: 添加 MongoDB 依赖 步骤 2: 配置 MongoDB 连接信息 步骤 3: 创建实体类 步骤 4: 创建 Repository 接口 步骤 5: 使用 Repository 进行操作 二、特殊处理 写在前面 在Spring Boot中集成MongoDB的过程相对简单,以下是一个…

Linux下使用宏定义判断系统架构和系统类型

文章目录 查看编译器当前支持的宏定义查找指定的宏不同架构不同系统 附录-编译器内部常用的一些宏定义宏定义实际应用使用宏定义判断系统架构使用宏定义判断系统类型 一般情况下在linux下做C/C方面的开发不需要太关注系统架构,当然如果涉及到不同架构下的适配问题&a…

Python---变量的作用域

变量作用域:指的是变量的作用范围(变量在哪里可用,在哪里不可用),主要分为两类:局部变量和全局变量。 定义在函数外部的变量就称之为全局变量; 定义在函数内部的变量就称之为局部变量。 # 定义…

基于 Eureka 的 Ribbon 负载均衡实现原理【SpringCloud 源码分析】

目录 一、前言 二、源码分析 三、负载均衡策略 一、前言 如下图,我们在 orderserver 中通过 restTemplate 向 usersever 发起 http 请求,在服务拉取的时候,主机名 localhost 是用服务名 userserver 代替的,那么该 url 是一个可…

Android Studio 引入Xui框架-简单应用

Android Studio Flamingo | 2022.2.1 Patch 2 Android 11开发、Gradle Version 8.0、 jdk17 源代码:GitHub - xuexiangjys/XUI: 💍A simple and elegant Android native UI framework, free your hands! (一个简洁而优雅的Android原生UI框架&#xff…

录屏软件自动开启录视频,是如何实现的?

工作要留痕,作为职场人的一项必备技能,因此许多人在做一些重要操作的时候,就会提前开启录屏软件,把操作的每一个步骤进行录制,以避免在出现问题的时候进行检查。当每天都需要在固定的时间点重复某项工作的时候&#xf…

【力扣】从零开始的动态规划

【力扣】从零开始的动态规划 文章目录 【力扣】从零开始的动态规划开头139. 单词拆分解题思路 45. 跳跃游戏 II解题思路 5. 最长回文子串解题思路 1143. 最长公共子序列解题思路 931. 下降路径最小和解题思路 开头 本力扣题解用5题来引出动态规划的解题步骤,用于本…

竞赛选题 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测?1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 🔥 优质竞赛项目系列,今天要分享的是 行人车辆目标检测计数系统 …

【计算机网络笔记】路由算法之距离向量路由算法

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…

DAY60 84.柱状图中最大的矩形

84.柱状图中最大的矩形 题目要求:给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼…

【docker】虚拟化和docker容器概念

基础了解 IAAS: 基础设施服务,(只提供基础设施,没有系统) **SAAS: ** 软件即服务,(提供基础设施和系统) PAAS: 平台即服务,(提供基…

《白帽子讲web安全》

第十四章 PHP安全 文件包含漏洞是“代码注入”的一种。“代码注入”这种攻击,其原理就是注入一段用户能控制的脚本或代码,并让服务器端执行。“代码注入”的典型代表就是文件包含(File Inclusion)。文件包含可能会出现在JSP、PHP…

时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测

时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测 目录 时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现HPO-ELM猎食者算法优化极限学习机时间序列预测 1.data为数据集…

【C++ 学习 ㊴】- 详解 C++ 的 I/O 流

目录 一、C 的 I/O 流 二、C 的标准 I/O 流 三、C 的文件 I/O 流 一、C 的 I/O 流 C 语言有一套完成数据读写(I/O)的解决方案: 使用 scanf()、gets() 等函数从键盘读取数据,使用 printf()、puts() 等函数向屏幕输出数据&#…

②【Hash】Redis常用数据类型:Hash [使用手册]

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Redis Hash ②Redis Hash 操作命令汇总1. hset…

Week-T10 数据增强

文章目录 一、准备环境和数据1.环境2. 数据 二、数据增强(增加数据集中样本的多样性)三、将增强后的数据添加到模型中四、开始训练五、自定义增强函数六、一些增强函数 🍨 本文为🔗365天深度学习训练营 中的学习记录博客&#x1f…

【Java】异常处理及其语法、抛出异常、自定义异常(完结)

🌺个人主页:Dawn黎明开始 🎀系列专栏:Java ⭐每日一句:道阻且长,行则将至 📢欢迎大家:关注🔍点赞👍评论📝收藏⭐️ 文章目录 一.🔐异…

Java,数据结构与集合源码,数据结构概述

目录 数据结构概念: 数据结构的研究对象: 研究对象一,数据间逻辑关系: 研究对象二,数据的存储结构(或物理结构): 研究对象三:运算结构 数据结构的相关介绍&#xff…

maven pom引入依赖不报红,但是项目Dependencies中没有引入jar包

前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注一下! 也许一个人独行,可以走的很快,但是一群人结伴而行,才能走的更远!让我们在成长的道路上互相学习&…