【模板方法】设计模式:构建可扩展软件的基石

本文主要介绍模板方法设计模式的定义、作用及使用场景

引言

在软件开发中,设计模式是解决常见问题的经过验证的解决方案。模板方法设计模式,作为行为型设计模式的一种,提供了一种在不牺牲灵活性的前提下定义算法框架的方法。
本文将深入探讨模板方法设计模式,包括其定义、结构、应用场景、优缺点以及实际案例分析。

定义

模板方法模式在一个方法中定义了一个算法框架,将一些步骤延迟到子类中实现。它使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。

模式结构

模板方法模式通常包含以下角色:

  • 抽象类(Abstract Class):定义了模板方法和一些基本方法(包括钩子方法和抽象方法)。
  • 具体类(Concrete Class):继承自抽象类并实现抽象方法。
public abstract class AbstractClass{public final void templateMethod(){// ... do somethingmethod1();// ... do somethingmethod2();// ... do something}protected abstract void method1();protected abstract void method2();
}public class ActionClass1 extends AbstractClass{@Overrideprotected void method1(){// ... do something}@Overrideprotected void method2(){// ... do something}
}
public class ActionClass2 extends AbstractClass{@Overrideprotected void method1(){// ... do something}@Overrideprotected void method2(){// ... do something}
}AbstractClass demo = new ActionClass1();
demo.templateMethod();

作用

复用

在模板方法中,将可变的部分留给子类去实现,所有的子类都可以复用父类中模板方法所定义的流程代码。
比如最常见的 InputStream,就用到了模板方法设计模式。


public abstract class InputStream implements Closeable {//...省略其他代码.../**模板方法,定义了读取数据的整个流程,且暴露了一个由子类去实现的抽象方法read()*/public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read();if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read();if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}public abstract int read() throws IOException; //子类去实现
}public class ByteArrayInputStream extends InputStream {//...省略其他代码...@Overridepublic synchronized int read() {return (pos < count) ? (buf[pos++] & 0xff) : -1;}
}

扩展

模板方法设计模式常用在框架的开发中,让框架的使用者可以在不修改框架源码的情况下,定制框架的功能。
比如HttpServletservice()方法就是一个模板方法,它实现了整个Http请求的执行流程,doGetdoPost是模板中可以由子类来定制的部分。

protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException
{String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {doGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < lastModified) {maybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}
}

优点

  • 高度的代码复用:通过共享不变的算法骨架,减少代码重复。
  • 灵活性与扩展性:子类可以在不改变算法结构的前提下,提供特定步骤的实现。
  • 松耦合:算法的骨架与具体实现解耦,提高了系统的可维护性。

应用场景

模板方法设计模式适用于以下场景:

  • 多步骤算法:需要执行一系列固定顺序的步骤,但某些步骤的具体实现可能不同。
  • 相似行为的家族:一组类具有相似的行为,但具体实现有所不同。
  • 需要控制扩展:希望控制子类的扩展,同时保持算法结构的一致性。

实战

关于实战内容,我将在后续的文章中来详述一下,我当时怎么利用模板方法设计模式+责任链设计模式来优化系统性能的。
今天,我只简单的聊一下,当时的背景是怎样的,为什么要进行系统优化。

背景

当时我负责的那个系统是财务系统,对财务熟悉的人应该知道,财务系统特别复杂,且在月初的时候需要进行账务核算。

在进行账务核算的时候,需要执行 10 个步骤,每一个步骤都是去登录不同的平台去执行。

  1. 登录应用服务器 1,执行 curl 命令;
  2. 登录数据库服务器,执行 sql;
  3. 登录应用服务器 2,执行 curl 命令;
  4. 用 postman 调用 python 接口。

只有当这 10 个步骤串行执行成功后,整个结账流程才算结束。
最开始负责这部分的同事,纯手工执行这 10 个步骤的,麻烦不说且十分耗时。

等我接手之后,对此进行了改造。
我们认真分析一下可以看出来,从步骤 1 到步骤 10 的执行,这不就很符合调度链吗,而且每一个步骤的执行都需要依赖前一个步骤执行成功且自己是未执行的状态,这不就是一个模板吗。

更详细的内容,我将作为一个单独的文章,更详细的展示出来。

结论与最佳实践

模板方法设计模式是一种强大的设计工具,它通过定义算法的骨架,提供了一种灵活而一致的方式来扩展系统。
在实际应用中,应该仔细考虑何时使用模板方法模式,以及如何设计抽象类和具体类,以确保系统的可维护性和可扩展性。

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

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

相关文章

Vant 组件库在Vue3的使用

Vant 是一个轻量、可靠的移动端组件库&#xff0c;专为 Vue.js 框架设计&#xff0c;提供了丰富的组件来加速移动端应用的开发。以下是关于 Vant UI 组件库以及在 Vue 3 中的使用方法的介绍。 Vant 组件库介绍 Vant 组件库拥有以下特点&#xff1a; 轻量化&#xff1a;组件平…

第五题:最长回文子串(Longest Palindromic Substring)

题目描述&#xff1a; 给定一个字符串 s&#xff0c;找到 s 中最长的回文子串。 示例&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" 或 "aba" 输入&#xff1a;s "cbbd" 输出&#xff1a;"bb" 要求…

开源接口自动化测试工具AutoMeter

AutoMeter是一款针对分布式服务和微服务API做功能和性能一体化的自动化测试平台。一站式提供项目管理&#xff0c;微服务&#xff0c;API接口&#xff0c;用例&#xff0c;环境管理&#xff0c;测试管理&#xff0c;前置条件&#xff0c;测试集合&#xff0c;变量管理&#xff…

【芯片设计- RTL 数字逻辑设计入门 9.4 -- Power Gating 在SoC 芯片电源完整性中的详细介绍】

文章目录 电源完整性简介电源完整性重要性电源完整性主要问题电源完整性问题优化什么是Power Gating?Power Gating的优势与挑战浪涌电流的产生与影响设计中的折中与优化电源完整性简介 电源完整性(Power Integrity, PI)是指在系统级设计中,确保电源分配网络(Power Distri…

kali安装

引言 Kali Linux 是一个基于 Debian 的 Linux 发行版&#xff0c;专门为渗透测试和安全审计而设计。它包含了大量的安全工具&#xff0c;如 Wireshark、Nmap、Metasploit 等&#xff0c;这些工具可以帮助安全专家和研究人员进行网络安全评估、漏洞检测和渗透测试。Kali Linux …

系统架构师(每日一练23)

每日一练 1.软件活动主要包括软件描述、()、软件有效性验证和()&#xff0c;()定义了软件功能及使用限制。答案与解析 问题1 A.软件模型 B.软件需求 C.软件分析 D.软件开发 问题2 A.软件分析 B.软件测试 C.软件演化 D.软件开发 问题3 A.软件分析 B.软件测试 C.软件描述 D.软…

进阶-5.锁

锁 1.概述2.全局锁3.表级锁3.1 介绍3.2 表锁3.3 元数据锁3.4意向锁 4.行级锁 1.概述 分类 按锁的粒度分类&#xff1a; 全局锁&#xff1a;锁住数据库中所有表表级锁&#xff1a;每次操作锁定整张表行级锁&#xff1a;每次操作锁定对应的行数据 2.全局锁 介绍 全局锁就是对…

第N11周:seq2seq翻译实战-Pytorch复现

任务&#xff1a; ●为解码器添加上注意力机制 一、前期准备工作 from __future__ import unicode_literals, print_function, division from io import open import unicodedata import string import re import randomimport torch import torch.nn as nn from torch impor…

Python中的变量:作用域与生命周期的秘密探索

引言 在编程的世界里&#xff0c;变量如同舞台上的演员&#xff0c;它们有着自己的“角色”——存储数据&#xff0c;也有着特定的“登场”和“退场”时刻&#xff0c;即作用域和生命周期。理解这些概念对于编写高效、可维护的代码至关重要。本文将带你一起探索Python中变量的…

一款好看的WordPress REST API 主题

介绍&#xff1a; 主题特色&#xff1a; 使用Nuxtjs WordPress Rest Api 实现前后端分离&#xff0c;可完成多端部署&#xff1b; 主题支持自动切换黑夜模式。 使用说明&#xff1a; service 目录为wordpress主题文件&#xff0c;需要拷贝到wordpress主题目录下&#xff0…

cmake install 区分Debug和Relase

需求&#xff1a; 在vs下界面运行install命令需要将生成的程序按relase和Debug安装到指定目录。 实现&#xff1a; 配置如下cmake set(CMAKE_INSTALL_PREFIX ${PUBLISH_DIR}) message(STATUS "PUBLISH_DIR dir:${PUBLISH_DIR}") install(TARGETS ${TARGET_NAME}…

记录一次经历:使用flask_sqlalchemy集成flask造成循环导入问题

前言&#xff1a; 工作需求&#xff0c;写一个接口&#xff0c;用Python来编写&#xff0c;我首先想到用flask小型框架来支撑&#xff0c;配置sqlalchemy来实现&#xff0c;但是在实现的过程中&#xff0c;发生循环导入问题 我想到用蓝图来解决此问题&#xff0c;但是仍然会出死…

基于PHP的文件上传

文件上传是现代网络应用中不可或缺的功能&#xff0c;它允许用户将本地文件存储到服务器上&#xff0c;用于后续的处理、分发或备份。 一、基于前端验证的文件上传 文件上传漏洞中的前端验证漏洞是一个常见且危险的问题。这类漏洞的产生主要是因为前端验证机制可以通过多种方…

设置虚拟机使用主机以太网而不是WiF连接

虚拟机使用主机的以太网连接而不是Wi-Fi连接&#xff0c;可以通过在虚拟化软件中配置虚拟机的网络设置来实现。以下是一些常见的虚拟化软件&#xff08;如VMware和VirtualBox&#xff09;中设置虚拟机网络以使用以太网连接的步骤&#xff1a; 一、VMware中设置 1、打开虚拟网…

微信小程序:点击事件(bindtap)传递参数

小程序在组件上绑定事件后&#xff0c;传递参数的方式不同于前端其他场景中直接加参数的方式&#xff0c;小程序在参数的传递时&#xff0c;采用事件对象的自定义属性的方式&#xff0c;具体实现如下&#xff1a; wxml&#xff1a; <view bindtap"goIndex" data…

JAVA双端队列Deque详解

Java中的双端队列&#xff08;Deque, 全称是double-ended queue&#xff09;是一种具有队列和栈的性质的抽象数据类型。双端队列中的元素可以从两端弹出&#xff08;在队列的头部和尾部进行添加或删除操作&#xff09;&#xff0c;因此它既可以作为FIFO&#xff08;先进先出&am…

天猫 登录滑块 淘系滑块分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关 前言 玩了几天现在才有空研究轨迹直接用了之前的…

UEditor百度富文本后端上传文件接口

UEditor百度富文本后端上传文件接口 直接上代码 接口&#xff1a; RequestMapping("/UEditorConfig")public String list(HttpServletRequest request, HttpServletResponse response) throws IOException {String config environment.getProperty("ueditor.c…

SOMEIP_ETS_059: ResetInterface_wrong_Fire_and_forget_package_get_No_Error_back

测试目的&#xff1a; 验证设备&#xff08;DUT&#xff09;在接收到一个错误的Fire&Forget消息时&#xff0c;不会做出响应或发送错误消息。 描述 本测试用例旨在检查DUT在接收到使用无效接口版本的方法resetInterface的Fire&Forget消息时&#xff0c;是否不会回应…

React 入门第四天:理解React中的路由与导航

在React学习的第四天&#xff0c;我将目光聚焦在React Router上。路由是任何单页应用&#xff08;SPA&#xff09;的核心部分&#xff0c;决定了用户如何在应用中导航&#xff0c;以及不同URL对应的内容如何渲染。通过学习React Router&#xff0c;我体会到了React处理路由的强…