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")

    @abstractmethod
    def brew(self):
        pass

    def pour_in_cup(self):
        print("Pouring into cup")

    @abstractmethod
    def 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 False

class 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, abstractmethod

class Logger(ABC):
    def log(self):
        self.connect()
        self.format_log()
        self.write_log()
        self.disconnect()

    @abstractmethod
    def connect(self):
        pass

    @abstractmethod
    def format_log(self):
        pass

    @abstractmethod
    def write_log(self):
        pass

    @abstractmethod
    def disconnect(self):
        pass

class 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♪(・ω・)ノ 🍇

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DeepStream--测试lpdnet车牌检测模型

模型地址:https://catalog.ngc.nvidia.com/orgs/nvidia/teams/tao/models/lpdnet/version 模型格式已经从加密的etlt格式变为onnx格式。这个模型用于从汽车图片上检测出车牌位置,模型有两个,一个用于美国车,一个用于中国车。 Nv…

Mysql之聚合函数

Mysql之聚合函数 什么是聚合函数常见的聚合函数GROUP BYWITH ROLLUPHAVINGHAVING与WHERE的对比 总结SQL底层原理 什么是聚合函数 对一组数据进行汇总的函数,但是还是返回一个结果 聚合函数也叫聚集,分组函数 常见的聚合函数 1.AVG(): 求平均值 2.SUM() :…

HarmonyOS基础组件之Button三种类型的使用

简介 HarmonyOS在明年将正式不再兼容Android原生功能,这意味着对于客户端的小伙伴不得不开始学习HarmonyOS开发语言。本篇文章主要介绍鸿蒙中的Button使用。 HarmonyOS中的Button相较于Android原生来说,功能比较丰富,扩展性高,减…

OpenShift 4 - 部署 RHODS 环境,运行 AI/ML 应用(视频)

《OpenShift / RHEL / DevSecOps 汇总目录》 说明:本文已经在 OpenShift 4.14 RHODS 1.33 的环境中验证 文章目录 RHODS 简介安装 RHODS 环境运行环境说明用 RHODS Operator 安装环境创建 Jupyter Notebook 运行环境 开发调式 AI/ML 应用部署运行 AI/ML 应用视频参…

国产压力测试工具的主要作用

国产压力测试工具可以帮助软件开发和维护团队对系统进行全面的性能测试,以评估系统在高负载下的性能表现。以下是国产压力测试工具的主要作用: 性能评估:国产压力测试工具可以模拟多用户同时对系统进行访问和操作,通过对系统的响应…

SpringBoot 自动装配原理 - 支付宝支付封装starter

SpringBoot 自动装配 SpringBoot 自动装配原理详细介绍自定义 Spring Boot Starter1.读取配置文件2.注册 AlipayClient bean3.核心代码编写4.注册 AlipayAPI bean5.编写 META-INF/spring.factories 文件6.项目结构测试1.创建一个测试项目,引入自定义 starter 依赖2.…

golang学习笔记——接口和继承比较1

继承 Go 语言的设计之初,就不打算支持面向对象的编程特性,因此 Go 不支持面向对象的三大特性之一——继承。但是 Go 可以通过组合的思想去实现 “继承”。继承是面向对象的三大特性之一,继承是从已有的类中派生出新的类,新的类能…

基数排序详解(LSD方法+MSD方法+思路+图解+代码)

文章目录 基数排序一、基数排序概念1.LSD排序法(最低位优先法)2.MSD排序法(最高位优先法) 基数排序 一、基数排序 概念 基数排序是一种非比较型整数排序算法 将整数按位数切割成不同的数字,然后按每个位数分别比较 …

函数有返回类型,但函数体未返回类型,程序崩溃问题记录

问题 使用类指针调用函数时&#xff0c;程序崩溃。 问题定位&#xff1a; name new nameSetting;name->setName("helloworld");qDebug().noquote() << name->getName();原因 class nameSetting { public:nameSetting();QString setName(const QStri…

短视频配音软件有哪些?这些常用的短视频配音软件

短视频行业近年来发展得很快&#xff0c;几乎闯入了我们每个现代人的生活&#xff0c;它以其独有的特点和乐趣&#xff0c;也收获了大批短视频爱好者&#xff0c;配音是短视频创作过程中不可或缺的环节&#xff0c;今天&#xff0c;我们就来聊聊短视频配音及好用的配音软件。 短…

关闭bitlocker加密

windows11的笔记本电脑买回来发现分驱都处于bitlocker状态&#xff0c;上网上搜索都是说进入控制面板的安全项进行关闭&#xff0c;包括去搜索栏搜索“管理 BitLocker”&#xff0c;对搜索出来的项打开&#xff0c;经过试验&#xff0c;它们进入的是同一个位置&#xff0c;只有…

详解Python安装requests库的实例代码

文章目录 前言基本用法基本的get请求带参数的GET请求解析json关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 前…

【20年扬大真题】编写对数组求逆的递归算法

【20年扬大真题】 编写对数组求逆的递归算法 void swap(int* a, int* b) {int tmp *b;*b *a;*a tmp; } void Ni(int arr[],int left,int right) {if (left > right) {return;}swap(&arr[left], &arr[right]);Ni(arr, left 1, right - 1); } int main() {int ar…

全网最全jmeter接口测试/接口自动化测试看这篇文章就够了:跨线程组传递jmeter变量及cookie的处理

setUp线程组 setUp thread group&#xff1a; 一种特殊类型的线程组&#xff0c;用于在执行常规线程组之前执行一些必要的操作。 在 setup线程组下提到的线程行为与普通线程组完全相同。不同的是执行顺序--- 它会在普通线程组执行之前被触发&#xff1b; 应用场景举例&#xf…

Oracle数据库笔记(一)

1.概述 Oracle版本 19c 在线迁移、自适应扫描、自适应数据共享11g 企业管理器、自动化诊断工具、自动化性能管理 Oracle特点 可用性强可扩展性强数据安全性强稳定性强 常见数据库 小 Access中 SQL Server、MySQL大 Oracle、DB2 2.数据、数据库、数据库管理系统、数据库系…

基于知识问答的上下文学习中的代码风格11.20

基于知识问答的上下文学习中的代码风格 摘要1 引言2 相关工作3 方法3.1 概述3.2 元函数设计3.3 推理 4 实验4.1 实验设置4.2 实施细节4.3 主要结果 摘要 现有的基于知识的问题分类方法通常依赖于复杂的训练技术和模型框架&#xff0c;在实际应用中存在诸多局限性。最近&#x…

redis运维(十二)

一 位图 ① 概念 1、说明&#xff1a;位图还是在操作字符串2、位图玩字符串在内存中存储的二进制3、ASCII字符通过映射转化为二进制4、操作的是字符串value ② ASCII字符铺垫 1、控制ASCII字符 2、ASCII可显示字符 ③ SETBIT 细节&#xff1a; setbit 命令的返回值是之…

算法分析与设计课后练习22

设W(5,7,10,12,15,18,20)和M35&#xff0c;使用过程SUMOFSUB找出W种使得和数等于M的全部子集并画出所生成的部分状态空间树

打破传统束缚,释放服务潜能:本地生活服务商聚合系统引领行业新风向!

本地生活服务商聚合系统是一种集合多平台、多项目的创新型服务系统&#xff0c;它打破了传统服务商系统的一对一限制&#xff0c;为创业者和运营商带来了诸多优势。小多将深入探讨本地生活服务商聚合系统的优势。 随着互联网的快速发展&#xff0c;本地生活服务也迎来了蓬勃的发…

Java实现围棋算法

围棋是一种源自中国的棋类游戏&#xff0c;也是世界上最古老、最复杂的棋类游戏之一。该游戏由黑白两方交替放置棋子在棋盘上进行&#xff0c;目的是将自己的棋子占据更多的空间&#xff0c;并将对手的棋子围死或吃掉&#xff0c;最终获得胜利。围棋不仅是一种游戏&#xff0c;…