设计模式-模板方法

2023-11-16

前言

当我们需要在一个算法的框架中定义算法的骨架,并将一些步骤的具体实现留给子类来完成时,模板方法模式是一种非常有用的设计模式。这篇博客将介绍模板方法模式的概念,并提供一个简单的Java代码示例来说明如何使用模板方法模式。

模板方法模式简介

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将算法中的一些步骤的具体实现延迟到子类中。这种模式有助于在不改变算法整体结构的情况下,允许子类定制算法的特定步骤。

模板方法模式包括以下主要角色:

  1. 抽象类(Abstract Class):定义算法的骨架,包括一个模板方法和一些抽象方法,这些抽象方法由子类来实现。

  2. 具体子类(Concrete Subclass):实现抽象类中的抽象方法,完成算法的具体步骤。

Java代码示例

假设我们正在开发一个咖啡和茶的制作应用程序。制作咖啡和茶的过程有一些共同的步骤,但也有一些特定于每种饮料的步骤。我们可以使用模板方法模式来处理这种情况。

首先,让我们创建一个抽象类 Beverage,它定义了制作饮料的模板方法以及一些抽象方法:

// 抽象类
public abstract class Beverage {
    // 模板方法,定义了制作饮料的算法骨架
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // 抽象方法,由子类实现
    protected abstract void brew();

    protected abstract void addCondiments();

    // 共同的步骤
    private void boilWater() {
        System.out.println("Boiling water");
    }

    private void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

接下来,我们可以创建具体的子类,分别表示咖啡和茶,实现它们的特定步骤:

// 具体子类:咖啡
public class Coffee extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

// 具体子类:茶
public class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

现在,我们可以在客户端代码中使用这些具体子类来制作咖啡和茶:

public class Main {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        Beverage tea = new Tea();

        System.out.println("Making coffee:");
        coffee.prepareBeverage();

        System.out.println("\nMaking tea:");
        tea.prepareBeverage();
    }
}

在这个示例中,抽象类 Beverage 定义了制作饮料的模板方法 prepareBeverage,并将一些共同的步骤封装在其中。具体子类 CoffeeTea 分别实现了特定的步骤。客户端代码可以使用这些具体子类来制作不同的饮料,而不需要了解制作的具体步骤。

这个示例展示了模板方法模式的核心思想,即定义算法的骨架,将一些步骤的实现留给子类,从而实现了代码的复用和扩展性。这种模式特别适用于具有共同步骤的算法家族。

模板方法使用场景

模板方法(Template Method)是一种行为型设计模式,它定义了一个算法的骨架,将算法中的一些步骤延迟到子类中实现。这个模式在以下情况下特别有用:

  1. 算法的骨架已经确定,但某些步骤的具体实现可以变化: 当你有一个算法,但其中的一些步骤可以根据不同的情况或需求而变化时,可以使用模板方法。它允许你在超类中定义通用的算法结构,而将特定的实现细节留给子类。

  2. 避免代码重复: 模板方法有助于避免在多个类中复制相似的代码。通过将共享的算法步骤放在超类中,你可以减少代码重复性,并使代码更容易维护。

  3. 确保一致性: 模板方法确保在算法中的每个步骤都以相同的顺序执行。这可以确保算法的行为是一致的,无论哪个子类实现了具体的步骤。

  4. 扩展性: 子类可以轻松地扩展或修改算法的某些部分,而不会影响整体算法结构。这使得代码更容易维护和扩展。

  5. 钩子方法: 模板方法通常包括一个或多个“钩子方法”,这些方法在超类中有默认实现,但子类可以选择性地覆盖它们以改变算法的行为。这种机制允许子类在不影响整个算法结构的情况下自定义部分行为。

  6. 标准化: 模板方法有助于定义一种标准的算法模式,这可以在整个项目或组织中得到复用,从而提高代码的一致性和可维护性。

举例来说,模板方法常常用于编写框架或库,其中定义了一些通用的操作流程,而具体的应用程序可以通过子类化来提供定制化的实现,同时保持整体架构的稳定性。一个经典的例子是Java中的Servlet生命周期方法,其中doGet()和doPost()等方法是模板方法,由开发者根据具体需求来实现。

模板方法使用场景

模板方法模式是一种常用的设计模式,通常在以下情况下使用:

  1. 算法的骨架已经确定,但某些步骤的具体实现可以变化: 当你有一个算法,但其中的一些步骤可以根据不同的情况或需求而变化时,可以使用模板方法。它允许你在超类中定义通用的算法结构,而将特定的实现细节留给子类。

  2. 避免代码重复: 模板方法有助于避免在多个类中复制相似的代码。通过将共享的算法步骤放在超类中,你可以减少代码重复性,并使代码更容易维护。

  3. 确保一致性: 模板方法确保在算法中的每个步骤都以相同的顺序执行。这可以确保算法的行为是一致的,无论哪个子类实现了具体的步骤。

  4. 扩展性: 子类可以轻松地扩展或修改算法的某些部分,而不会影响整体算法结构。这使得代码更容易维护和扩展。

  5. 钩子方法: 模板方法通常包括一个或多个“钩子方法”,这些方法在超类中有默认实现,但子类可以选择性地覆盖它们以改变算法的行为。这种机制允许子类在不影响整个算法结构的情况下自定义部分行为。

  6. 标准化: 模板方法有助于定义一种标准的算法模式,这可以在整个项目或组织中得到复用,从而提高代码的一致性和可维护性。

具体的使用场景包括但不限于:

  • 图形界面应用程序中的窗口、对话框等构建: 不同类型的窗口或对话框可能具有相似的构建步骤,但具体实现可能不同。

  • 数据访问层的实现: 在数据库访问中,可以定义一个通用的数据访问方法,但具体的 SQL 查询或 NoSQL 操作可以在子类中实现。

  • 游戏开发中的游戏角色: 游戏中的不同角色可能共享某些行为,但具有不同的特殊技能或动作。

  • 文档生成工具: 在文档生成工具中,可以定义一个通用的文档生成算法,但具体的文档格式或输出方式可以由子类定义。

总之,模板方法模式在任何需要定义算法骨架并允许子类提供特定实现的情况下都是有用的。它有助于提高代码的复用性、可维护性和可扩展性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式-模板方法 的相关文章

  • 如何在ipywidget按钮中显示全文?

    我正在创建一个ipywidget带有一些文本的按钮 但按钮中未显示全文 我使用的代码如下 import ipywidgets as widgets from IPython display import display button wid
  • Flask如何获取请求的HTTP_ORIGIN

    我想用我自己设置的 Access Control Allow Origin 标头做出响应 而弄清楚请求中的 HTTP ORIGIN 参数在哪里似乎很混乱 我在用着烧瓶 0 10 1 以及HTTP ORIGIN似乎是这个的特点之一object
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • Fabric env.roledefs 未按预期运行

    On the 面料网站 http docs fabfile org en 1 10 usage execution html 给出这个例子 from fabric api import env env roledefs web hosts
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • 如何在seaborn displot中使用hist_kws

    我想在同一图中用不同的颜色绘制直方图和 kde 线 我想为直方图设置绿色 为 kde 线设置蓝色 我设法弄清楚使用 line kws 来更改 kde 线条颜色 但 hist kws 不适用于显示 我尝试过使用 histplot 但我无法为
  • 每个 X 具有多个 Y 值的 Python 散点图

    我正在尝试使用 Python 创建一个散点图 其中包含两个 X 类别 cat1 cat2 每个类别都有多个 Y 值 如果每个 X 值的 Y 值的数量相同 我可以使用以下代码使其工作 import numpy as np import mat
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • 为字典中的一个键附加多个值[重复]

    这个问题在这里已经有答案了 我是 python 新手 我有每年的年份和值列表 我想要做的是检查字典中是否已存在该年份 如果存在 则将该值附加到特定键的值列表中 例如 我有一个年份列表 并且每年都有一个值 2010 2 2009 4 1989
  • 解释 Python 中的数字范围

    在 Pylons Web 应用程序中 我需要获取一个字符串 例如 关于如何做到这一点有什么建议吗 我是 Python 新手 我还没有找到任何可以帮助解决此类问题的东西 该列表将是 1 2 3 45 46 48 49 50 51 77 使用
  • Google App Engine 如何预编译 Java?

    App Engine 对应用程序的 Java 字节码使用 预编译 过程 以增强应用程序在 Java 运行时环境中的性能 预编译代码的功能与原始字节码相同 有没有详细的信息这是做什么的 我在一个中找到了这个谷歌群组消息 http groups
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 如何计算 pandas 数据帧上的连续有序值

    我试图从给定的数据帧中获取连续 0 值的最大计数 其中包含来自 pandas 数据帧的 id date value 列 如下所示 id date value 354 2019 03 01 0 354 2019 03 02 0 354 201
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • 使用 Python 的 matplotlib 选择在屏幕上显示哪些图形以及将哪些图形保存到文件中

    我想用Python创建不同的图形matplotlib pyplot 然后 我想将其中一些保存到文件中 而另一些则应使用show 命令 然而 show 显示all创建的数字 我可以通过调用来避免这种情况close 创建我不想在屏幕上显示的绘图
  • 如何使用 Pycharm 安装 tkinter? [复制]

    这个问题在这里已经有答案了 I used sudo apt get install python3 6 tk而且效果很好 如果我在终端中打开 python Tkinter 就可以工作 但我无法将其安装在我的 Pycharm 项目上 pip

随机推荐

  • java类中获取ServletContext的方法

    在项目中遇到这样一个问题 需要在没有web请求的java普通类中 获取ServletContext 那么该怎么获取呢 答案就是通过ContextLoader类 WebApplicationContext webAc ContextLoade
  • 【华为OD机试 2023】 匿名信(C++ Java JavaScript Python)

    华为od机试题库 华为OD机试2022 2023 C Java JS Py https blog csdn net banxia frontend category 12225173 html 华为OD机试2023最新题库 更新中 C Ja
  • NHibernet Unable to locate persister for the entity

    第一 xml文件必须为 hbm xml 第二 设置xml文件为嵌入的资源 用鼠标点击右键 然后生成操作里 选择嵌入的资源即可解决 https www cnblogs com lyj 转载于 https www cnblogs com xia
  • SSD预测错误调试:RuntimeError: index_select(): functions with out=... arguments don‘t support automatic dif

    一 错误 运行SSD pytorch版本时 运行test py时 遇到这种错误 RuntimeError index select functions with out arguments don t support automatic d
  • Kafka面试必问几个概念 与 使用场景

    介绍下我写的这个kafka项目 里面做了详细的配置注释已经代码的demo 可供大家学习 项目 地址 springboot kafka集群项目实战 kafka集群批量消费数据去重和一致性 kafka的几个重要概念 接下来围绕下面几个概念来进行
  • 运放中接电容的作用

    运放概述 案例讲解 运算分析 一 基本概念 反向放大器 优点 两个输入端电位始终近似为零 同相端接地 反相端虚地 只有差模信号 抗干扰能力强 缺点 输入阻抗很小 等于信号到输入端的串联电阻的阻值 同相放大器 优点 输入阻抗和运放的输入阻抗相
  • 《JavaScript高级程序设计(第四版)》红宝书学习笔记(2)(第四章:变量、作用域与内存)

    个人对第四版红宝书的学习笔记 不适合小白阅读 这是part2 持续更新 其他章节笔记看我主页 记 的表示是ES6新增的知识点 记 表示包含新知识点 第四章 变量 作用域与内存 4 1 原始值与引用值 ECMAScript变量可以包含两种不同
  • C获取linux系统环境变量方法(Environment Variables)

    主要有三种方法 都很简单 1 一个单纯c语言获取的方式 span style font family none font size 14px include span
  • Java系列8—对象创建的内存分配和构造方法

    对象的创建 类和对象的区别 面向对象 java语言的核心机制 最重要的内容 java语言的特色 面向过程和面向对象的区别 面向过程 主要关注点是 实现的具体过程 因果关系 面向对象 主要关注对象 独立体 能完成哪些功能 优点 耦合度低 扩展
  • 态势感知(SIP)

    SIP态势感知 一 SIP态势感知概述 1 业界标准 数据来源 gt 智能分析 gt 安全可视 gt 协同响应 通过日志采集探针和流量传感器分别进行不同系统日志和流量日志的采集和处理任务 通过对海量数据进行多维度快速 自动化的关联分析发现本
  • 跨框架解决方案-Mitosis【问题与局限】

    不要定义与状态属性同名的变量 async方法不能定义在state内 函数不能通过引用直接传递给JSX回调函数 可以在回调函数中定义一个匿名函数 不能将 params 分配给 state 不能将函数输出分配给 state state不能被解构
  • dart 相关资源收集

    百丈高楼平地起 要想写好flutter 必先学号dart 资源 给 Android 开发者的 Dart 教程 学好 Dart 才能玩转 Flutter
  • ms-repeat 数据渲染后触发事件

    ms repeat 数据渲染后触发 data repeat rendered 例子 div class timebox h3 el year 年 el month 月 h3 ul li li ul div
  • MVC设计思想

    1 MVC思想的说明 经典MVC模式中 M是指业务模型 V是指用户界面 C则是控制器 使用MVC的目的是将M和V的实现代码分离 从而使同一个程序可以使用不同的表现形式 其中 View的定义比较清晰 就是用户界面 M model 业务模型 V
  • 24个笔画顺序表_语文老师整理:560个小学常用汉字笔画笔顺表!小学阶段多练习...

    今天给大家分享的是资深语文老师整理的学习资料 560个小学常用汉字笔画笔顺表 家里有小学生的家长 建议帮孩子存好 小学阶段多练习 不仅对语文学习的提高有帮助 还能培养孩子的语文素养 在小学语文的学习中 汉字是最基础的知识点 孩子在学习语文的
  • Codeforces Round #561 (Div. 2)ABC

    三个题 各位大佬别喷我 我很菜 A Silent Classroom There are n students in the first grade of Nlogonia high school The principal wishes
  • 【03】上下文

    基于智能 合约的安全企业对消费者供应链系统在农产品供应链中使用区块链和智能 合约进行追溯链上 链下 智能 合约的可扩展和隐私保护设计TinyEVM 低功耗物联网设备上的链下 智能 合约区块链技术中的智能 合约和用例概述Blockumulus
  • Java的8种基本数据类型

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 前言 Java数据类型分为两大类 基本数据类型 引用类型 如图所示 下面讲解的是Java的八种基本数据类型 一 按照数据类型来分 1 整
  • 西门子变频器SINAMICS S120电源模块分享

    西门子变频器SINAMICS S120系列 在工业领域中能胜任各种要求严格的驱动控制任务 为用户提供简单有效的驱动控制过程 西门子变频器SINAMICS S120系列可以配置电源模块 来为西门子变频器驱动控制系统提供稳定的电源保障 本文下面
  • 设计模式-模板方法

    文章目录 前言 模板方法模式简介 Java代码示例 模板方法使用场景 模板方法使用场景 前言 当我们需要在一个算法的框架中定义算法的骨架 并将一些步骤的具体实现留给子类来完成时 模板方法模式是一种非常有用的设计模式 这篇博客将介绍模板方法模