【软件设计模式之模板方法模式】

文章目录

  • 前言
  • 一、什么是模板方法模式?
  • 二、模板方法模式的结构
    • 1. 抽象类定义
    • 2. 具体实现
  • 三、模板方法模式的应用场景
    • 1. 算法重用
    • 2. 操作中的固定步骤
    • 3. 扩展框架的功能
    • 4. 提供回调方法
    • 5. 遵循开闭原则
  • 四、模板方法模式的优缺点
    • 1. 优点
      • 代码复用
      • 扩展性好
      • 符合开闭原则
    • 2. 缺点
      • 可能导致类的数量增加
      • 增加了系统的复杂度
  • 五、实战案例
    • 抽象类定义
    • 具体实现
      • 文本帖子
      • 图片帖子
      • 视频帖子
    • 使用示例

前言

模板方法模式是一种基于继承的设计模式。它的核心在于定义一个算法的框架,同时允许子类在不改变算法整体结构的情况下重写算法的某些特定步骤。这种方式不仅保证了算法步骤的一致性,而且提供了足够的灵活性,以适应不同的情境需求。

一、什么是模板方法模式?

模板方法模式是一种行为设计模式,这种模式的主要目的是定义一个操作中的算法骨架,并将具体的实施细节延迟到子类中。这样做的主要优势在于算法的结构可以在不改变的情况下,在子类中重新定义某些特定的步骤。

具体来说,模板方法模式通常涉及两个主要部分:一个抽象类和一个或多个具体实现。抽象类定义了算法的框架和执行算法的方法,这个方法称为模板方法。它包括一系列定义良好的步骤,其中一些步骤是抽象的,留给子类来实现。这种设计允许模板方法固定算法的结构,确保按照特定顺序执行步骤,同时提供足够的灵活性来让子类实现具体的行为。

这种模式在软件开发中非常有用,尤其是当多个类中的算法有共同的部分但在某些方面又有所不同时。通过模板方法模式,可以最大化地重用代码,减少冗余,并提高系统的可维护性。此外,由于它遵循了开闭原则(即对扩展开放,对修改封闭),因此有助于创建灵活且可扩展的系统。

二、模板方法模式的结构

模板方法模式的结构主要包括两个核心部分:抽象类定义和具体类实现。这种结构允许算法的步骤在抽象层面上被定义,同时提供灵活性,以便在具体类中定制这些步骤的实现。下面是模板方法模式的详细结构说明:

1. 抽象类定义

在模板方法模式中,抽象类定义了执行算法的模板方法。这个模板方法设置了一个算法的基本框架,指定了算法的骨架和执行的步骤序列。

abstract class AbstractClass {public final void templateMethod() {primitiveOperation1();primitiveOperation2();concreteOperation();hook();}// 可以定义一些具体方法final void concreteOperation() {// 这里可以有一些默认的实现}// 定义一些抽象方法,留给子类实现abstract void primitiveOperation1();abstract void primitiveOperation2();// 钩子方法,子类可以视情况决定是否覆盖它void hook() {}// ... 其他方法定义 ...
}

在这个抽象类中,templateMethod 是一个模板方法,它定义了算法的框架。primitiveOperation1primitiveOperation2 是抽象方法,留给子类实现具体的功能。concreteOperation 是一个具体方法,提供了默认的实现。hook 是一个钩子方法,它提供了一个扩展点,子类可以选择性地覆盖它以提供特定的行为。

2. 具体实现

具体类继承自抽象类并实现其抽象方法,提供算法步骤的具体实现。这样,不同的具体类可以以不同的方式实现这些步骤,而算法的结构仍由抽象类中的模板方法控制。

class ConcreteClass extends AbstractClass {@Overrideprotected void primitiveOperation1() {// 具体的实现1}@Overrideprotected void primitiveOperation2() {// 具体的实现2}// 子类可以选择覆盖钩子方法@Overridevoid hook() {// 特定于子类的钩子方法实现}// ... 其他方法实现 ...
}

在这个具体类中,primitiveOperation1primitiveOperation2 提供了抽象方法的具体实现,而可选的 hook 方法允许在算法的特定点进行微调。通过这种方式,模板方法模式使得算法的结构固定下来,同时又能在子类中提供足够的灵活性来实现具体的行为。

三、模板方法模式的应用场景

1. 算法重用

当多个类中的算法有共同的行为但在某些步骤上需要不同的实现时,模板方法模式非常有用。例如,在数据处理应用中,多个数据解析器可能共享相同的数据加载和清洗步骤,但在数据解析的步骤上各不相同。通过模板方法模式,可以重用公共步骤的代码,同时允许每个解析器定制其特定的解析逻辑。

2. 操作中的固定步骤

在某些操作中,步骤的顺序是固定的,但每个步骤的具体实现可能会有所不同。例如,在构建工具中,构建过程(编译、链接、打包等)的步骤是固定的,但针对不同类型的项目(如Java项目、C++项目)这些步骤的具体实现会有所不同。模板方法模式允许定义一个固定的操作流程,同时提供自定义这些步骤的能力。

3. 扩展框架的功能

在框架设计中,模板方法模式可用于定义框架的核心流程,同时允许用户通过继承来扩展框架的功能。例如,一个Web框架可能会定义请求处理的基本流程,而允许用户通过重写特定方法来自定义请求的预处理、处理和后处理逻辑。

4. 提供回调方法

在需要为特定事件或条件提供回调方法的场景中,模板方法模式可以非常有效。例如,在图形用户界面(GUI)库中,可以使用模板方法来定义事件处理的基本结构(如点击事件),同时允许用户通过重写方法来提供特定的事件处理逻辑。

5. 遵循开闭原则

当需要设计遵循开闭原则的系统时,模板方法模式是一个很好的选择。这种模式允许系统在不修改现有代码的情况下,通过扩展新的子类来增加新的行为。

四、模板方法模式的优缺点

模板方法模式是一种在软件设计中常用的模式,它具有一些显著的优点,但也存在一些缺点。理解这些优缺点有助于更好地决定何时使用此模式。

1. 优点

代码复用

  • 标准化流程: 模板方法模式允许在抽象类中定义标准化的流程或算法框架,减少了重复代码。
  • 维护性: 由于核心算法在一个地方定义和维护,所以当核心流程变化时,只需修改抽象类。

扩展性好

  • 灵活性: 通过在子类中实现抽象方法,可以在不修改现有代码的情况下扩展功能。
  • 自定义: 用户可以根据需求自定义特定的步骤,提高了模式的适用性。

符合开闭原则

  • 开闭原则: 模板方法模式很好地遵循了开闭原则,即对扩展开放,对修改封闭,有利于构建稳定且灵活的系统。

2. 缺点

可能导致类的数量增加

  • 类膨胀: 如果有许多稍微不同的算法变种,可能导致子类数量迅速增加。
  • 管理难度: 随着子类数量的增加,管理和维护这些类变得更加困难。

增加了系统的复杂度

  • 理解难度: 对于新开发人员来说,理解整个框架的流程和扩展点可能比较困难。
  • 紧密耦合: 模板方法模式通常意味着子类与抽象类之间的紧密耦合,这可能限制了子类的使用场景。

五、实战案例

假设我们正在开发一个简化的社交媒体应用,其中包括不同类型的帖子发布流程,比如文本帖子、图片帖子和视频帖子。尽管每种帖子的发布细节不同,但它们都遵循相同的基本流程:准备内容、格式化内容、发布到平台。可以使用模板方法模式来实现这一功能。

抽象类定义

定义一个抽象类 SocialMediaPost,它包含发布帖子的模板方法以及几个抽象方法,这些抽象方法将在子类中具体实现。

abstract class SocialMediaPost {// 模板方法定义发布流程public final void publishPost() {prepareContent();formatContent();postToPlatform();}// 准备内容的步骤abstract void prepareContent();// 格式化内容的步骤abstract void formatContent();// 发布到平台的步骤abstract void postToPlatform();
}

具体实现

创建几个具体的类来实现不同类型的帖子。

文本帖子

class TextPost extends SocialMediaPost {@Overridevoid prepareContent() {System.out.println("Preparing text content...");}@Overridevoid formatContent() {System.out.println("Formatting text content...");}@Overridevoid postToPlatform() {System.out.println("Posting text content to platform...");}
}

图片帖子

class ImagePost extends SocialMediaPost {@Overridevoid prepareContent() {System.out.println("Preparing image content...");}@Overridevoid formatContent() {System.out.println("Formatting image content...");}@Overridevoid postToPlatform() {System.out.println("Posting image content to platform...");}
}

视频帖子

class VideoPost extends SocialMediaPost {@Overridevoid prepareContent() {System.out.println("Preparing video content...");}@Overridevoid formatContent() {System.out.println("Formatting video content...");}@Overridevoid postToPlatform() {System.out.println("Posting video content to platform...");}
}

使用示例

在应用程序中,我们可以根据需要创建不同类型的帖子,并调用其 publishPost 方法来发布。

public class Main {public static void main(String[] args) {SocialMediaPost textPost = new TextPost();textPost.publishPost(); // 发布文本帖子SocialMediaPost imagePost = new ImagePost();imagePost.publishPost(); // 发布图片帖子SocialMediaPost videoPost = new VideoPost();videoPost.publishPost(); // 发布视频帖子}
}

在这个实战案例中,模板方法模式使得我们能够定义发布帖子的基本流程,同时允许在不同类型的帖子中定制内容准备、格式化和发布的具体细节。这样不仅保证了流程的一致性,而且提供了足够的灵活性来处理各种类型的帖子。

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

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

相关文章

[深度学习]yolov9+deepsort+pyqt5实现目标追踪

【YOLOv9DeepSORTPyQt5追踪介绍】 随着人工智能技术的飞速发展,目标追踪在视频监控、自动驾驶等领域的应用日益广泛。其中,YOLOv9作为先进的目标检测算法,结合DeepSORT多目标追踪算法和PyQt5图形界面库,能够为用户提供高效、直观…

Linux fdisk命令教程:硬盘分区的利器(附实例详解和注意事项)

Linux fdisk命令介绍 fdisk(format disk)是一个在Linux中用于创建和操作磁盘分区表的对话驱动命令。它是最常用的创建分区的工具之一。fdisk允许你在硬盘上创建和操作分区表。需要注意的是,fdisk是一个危险的工具,应该谨慎使用。…

前端笔记——var let const 之间的区别

Var: 关键字来声明变量。它有以下特点: var声明的变量作用域是函数级的,即在函数内部声明的变量在整个函数范围内可见。 var变量可以被重复声明,而不会引发错误。 var变量会存在变量提升(hoisting)现象&…

python-可视化篇-简单-条形图输出主要省份GDP排名情况

条形图输出主要省份GDP排名情况 代码 gdp广东:97277.77:107671.07 江苏:92595.40:99631.52 山东:76469.70:71067.5 浙江:56197.00:62353 河南:48055.90:54259.2 四川:40678.10:46615.82 湖北:39366.60:45828.31 湖南:36425.78:39752.12 河北:36010.30:35104.5 福建:35804.04:…

windows安装 RabbitMQ

首先打开 RabbitMQ 官网,点击 Get Started(开始) 点击 Download Installation(下载安装)。 这里提供了两种方式进行安装,我们使用第二种方法。 使用 chocolatey以管理用户身份使用官方安装程序 往下滑,第二种方法需要 Erlang 的依赖&#x…

iotdb集群模式部署

iotdb集群模式部署 重要声明:部署的版本要和脚本对应上,这里可以点击 来获取最新的脚本; 我使用的是1.3.0版本的iotdb 下面是我基于三个节点的部署步骤: 假如有三台物理机,里面安装了centos系统,它们的hostname分别是iotdb-1、iotdb-2、iotdb-3 1、设置网络 vim /…

1248 - Every derived table must have its own alias

该问题是子查询内的列名无法在外部查询中直接引用,使用别名来为子查询结果集命名,然后在外部查询中引用该别名。以下是一个修正后的查询语句: SELECT last_name, salary FROM (SELECT last_name, salary, RANK() OVER (ORDER BY salary DES…

avidemux-一个免费的视频编辑器,用于剪切、过滤和编码项目

avidemux-一个免费的视频编辑器,用于剪切、过滤和编码项目 avidemux-一个免费的视频编辑器,用于剪切、过滤和编码项目avidemux下载avidemux源代码参考资料 avidemux-一个免费的视频编辑器,用于剪切、过滤和编码项目 avidemux下载 avidemux …

mongoose httpserver浅析

文章目录 前言一、结构体及其功能二、函数MG_LOGmg_http_listenmg_mgr_poll question参考链接 前言 mongoose是一款基于C/C的网络库,可以实现TCP, UDP, HTTP, WebSocket, MQTT通讯。mongoose是的嵌入式网络程序更快、健壮,易于实现。 mongoose只有mong…

qt波位图

1&#xff0c;QPainter 绘制&#xff0c;先绘制这一堆蓝色的东西, 2&#xff0c;在用定时器&#xff1a;QTimer&#xff0c;配合绘制棕色的圆。用到取余&#xff0c;取整 #pragma once#include <QWidget> #include <QPaintEvent>#include <QTimer>QT_BEGIN_…

LangChain Agent v0.2.0简明教程 (上)

快速入门指南 – LangChain中文网 langchain源码剖析系列课程 九天玩转Langchain! 1. LangChain是什么2. LangChain Expression Language (LCEL)Runnable 接口3. Model I/O3.1 Prompt Templates3.2 Language Model3.3 Output ParsersUse case(Q&A with RAG)1. LangChain…

JavaScript中setout函数“bug”再研究

引言 在JavaScript中setout中函数不加双引号引发错误的问题-CSDN博客 上篇文章中笔者讲解了settimeout全局函数&#xff0c;关于引用函数时加不加双引号会使得延迟是否正常出现的“bug” 这里再详细阐述一下 实现方法 首先打开vscode&#xff0c;分别写入如下代码 <!DOC…

【踩坑】PyTorch中指定GPU不生效和GPU编号不一致问题

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 指定GPU不生效问题 解释&#xff1a;就是使用os.environ["CUDA_VISIBLE_DEVICES"] "1"后&#xff0c;后面使用起来仍然是cuda0. 解决&#xff1a;在最开头就使用 import os os.environ[&…

sentinel整合nacos在gateway中实现限流

sentinel整合nacos在gateway中实现限流 一、应用层面完成网关整合nacos和sentinel实现限流 前沿 启动nacos与sentinel的jar的启动&#xff0c;这里不细讲 sentinel官网 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 sentinel 下载地址 https://github.com/…

Spring中事务失效的场景

一:异常捕获处理 事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉 解决 在catch块添加throw new RuntimeException(e)抛出 二: 抛出检查异常 原因: Spring默认只会回滚非检查异常 解决: 配置rollbackFor属性 Transa…

使用uniapp实现小程序获取wifi并连接

一、背景 因业务需求&#xff0c;需要在小程序实现发现wifi和连接wifi。但由于Andriod和IOS有差异&#xff0c;所以实现起来有所区别。 先看官方文档 https://developers.weixin.qq.com/miniprogram/dev/framework/device/wifi.html 把连接基础流程了解后&#xff0c;发现二者流…

LeetCode题练习与总结:最接近的三数之和

一、题目 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数&#xff0c;使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 二、解题思路 解决这个问题的关键在于找到一个有效的算法来遍历数组并找到三…

车载电子电器架构 —— 电气架构开发计划

车载电子电器架构 —— 电气架构开发计划 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

实现KingSCADA系统按钮弹窗出现位置随点击位置变化。

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 在用KingSCADA做项目时&#xff0c;当我们点击不同的控制按钮&#xff0c;都可以弹出对应的控制弹窗。 在常规不做设置的情况下弹窗都是出现在固定的位置&#xff0c;要么一直出现在左上角&#xff0c;要么一直出现在…

【Java】常用实用类及java集合框架(实验六)

目录 一、实验目的 二、实验内容 三、实验小结 3.1 常用实用类 3.2 Java集合框架 一、实验目的 1、掌握java常用类的方法 2、掌握String类与数值类型数据的相互转化 3、掌握正则表达式的应用 4、掌握常用集合的创建和操作方法 二、实验内容 1、菜单的内容如下&#x…