Gof23设计模式之模板方法模式

2023-11-10

1.定义

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

2.结构

模板方法(Template Method)模式包含以下主要角色:

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。

    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

    • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

      • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。

      • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。

      • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

        一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

3.案例实现

/**
 * @author 晓风残月Lx
 * @date 2023/7/21 16:47
 *      抽象类(定义模板方法和基本方法)
 */
public abstract class AbstractClass {

    // 模板方法  加上final不让子类改变方法结构
    public final void cookProcess() {
        // 第一步,倒油
        this.pourOil();
        // 第二步,热油
        this.heatOil();
        // 第三步,倒蔬菜
        this.pourVegetable();
        // 第四步,倒调味料
        this.pourSauce();
        // 第五步,翻炒
        this.fry();
    }

    // 抽象方法
    public abstract void pourSauce();

    public abstract void pourVegetable();


    // 具体方法
    private void fry() {
        System.out.println("翻炒");
    }

    private void heatOil() {
        System.out.println("热油");
    }

    private void pourOil() {
        System.out.println("倒油");
    }

}

/**
 * @author 晓风残月Lx
 * @date 2023/7/25 0:46
 *      炒包菜类  具体的类
 */
public class ConcreteClass_BaoCai extends AbstractClass {
    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }

    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是包菜");
    }
}

/**
 * @author 晓风残月Lx
 * @date 2023/7/25 0:46
 *      炒菜芯类  具体的类
 */
public class ConcreteClass_CaiXin extends AbstractClass {
    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }

    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是菜芯");
    }
}

/**
 * @author 晓风残月Lx
 * @date 2023/7/25 0:48
 */
public class Client {

    public static void main(String[] args) {
        // 炒包菜
        // 创建对象
        ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
        baoCai.cookProcess();

        // 炒菜芯
        ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();
        caiXin.cookProcess();
    }
}

4.优缺点

优点:

  • 提高代码复用性

    将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。

  • 实现了反向控制

    通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 ,并符合“开闭原则”。

缺点:

  • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

5.使用场景

  • 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

6.JDK源码解析

InputStream类就使用了模板方法模式。在InputStream类中定义了多个 read() 方法,如下:

public abstract class InputStream implements Closeable {
    //抽象方法,要求子类必须重写
    public abstract int read() throws IOException;

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    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(); //调用了无参的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;
    }
}

从上面代码可以看到,无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。

在该方法中第18行、27行,可以看到调用了无参的抽象的 read() 方法。

总结如下: 在InputStream父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个索引位置,读取len个字节数据。具体如何读取一个字节数据呢?由子类实现。

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

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

  • 带有 Android 支持库 v7 的 Maven Android 插件

    我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • Android 中的列表(特别是 RecyclerView 和 CardView)如何工作

    请原谅我问这个问题 但我是 Android 开发新手 尽管我正在尝试了解developer android com 网站上的基础知识 但大多数示例 即使他们说它们是为 Android Studio 构建的 尚未设置为使用 Gradle 因此
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • 如何使用 JAVA 代码以编程方式捕获线程转储?

    我想通过 java 代码生成线程转储 我尝试使用 ThreadMXBean 为此 但我没有以正确的格式获得线程转储 因为我们正在使用jstack命令 请任何人提供一些帮助 他们是否有其他方式获取线程转储 使用任何其他 API 我想要的线程转
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

    这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Android蓝牙java.io.IOException:bt套接字已关闭,读取返回:-1

    我正在尝试编写一个代码 仅连接到运行 Android 5 0 KitKat 的设备上的 目前 唯一配对的设备 无论我尝试了多少方法 我仍然会收到此错误 这是我尝试过的最后一个代码 它似乎完成了我看到人们报告为成功的所有事情 有人能指出我做错
  • 如何使用正则表达式验证 1-99 范围?

    我需要验证一些用户输入 以确保输入的数字在 1 99 范围内 含 这些必须是整数 Integer 值 允许前面加 0 但可选 有效值 1 01 10 99 09 无效值 0 007 100 10 5 010 到目前为止 我已经制定了以下正则
  • 从直方图计算平均值和百分位数?

    我编写了一个计时器 可以测量任何多线程应用程序中特定代码的性能 在下面的计时器中 它还会在地图中填充花费了 x 毫秒的调用次数 我将使用这张图作为我的直方图的一部分来进行进一步的分析 例如调用花费了这么多毫秒的百分比等等 public st
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 用于缓存的 Servlet 过滤器

    我正在创建一个用于缓存的 servlet 过滤器 这个想法是将响应主体缓存到memcached 响应正文由以下方式生成 结果是一个字符串 response getWriter print result 我的问题是 由于响应正文将不加修改地放
  • 如何从日期中删除毫秒、秒、分钟和小时[重复]

    这个问题在这里已经有答案了 我遇到了一个问题 我想比较两个日期 然而 我只想比较年 月 日 这就是我能想到的 private Date trim Date date Calendar calendar Calendar getInstanc
  • 无法在 Java/Apache HttpClient 中处理带有垂直/管道栏的 url

    例如 如果我想处理这个网址 post new HttpPost http testurl com lists lprocess action LoadList 401814 1 Java Apache 不允许我这么做 因为它说竖线 是非法的
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 禁用 Android 菜单组

    我尝试使用以下代码禁用菜单组 但它不起作用 菜单项仍然启用 你能告诉我出了什么问题吗 资源 菜单 menu xml menu menu

随机推荐

  • Xor Sum 2二分/尺取 区间异或和等于区间和的方案数

    题目描述 There is an integer sequence A of length N Find the number of the pairs of integers l and r 1 l r N that satisfy th
  • pandas读写csv excel pinkle 的性能比较

    在数据分析工作中 csv excel pinkle这三种格式的文件经常会被用到 但是pandas读取这3种格式的数据究竟性能如何呢 我准备了13列 17519行的excel数据 测试了一下 结果是这样 csv xls pickle 字节数M
  • 计算机系统基础实验:认识logisim软件、门电路逻辑功能测试(仿真)

    通过logisim对逻辑电路进行分析 文章目录 目录 文章目录 前言 一 使用工具 二 实验过程 1 门电路绘制 2 真值表 总结 前言 计算机系统基础也开了实验课 实验内容是利用logisim软件进行测试门电路和逻辑芯片的逻辑功能 于是在
  • 在百度上搜不到的资源是在哪找的?就在这些强大的资源搜索网站呀

    都说又不懂的问 度娘 最快 但是也有一些东西是在 度娘 哪里也找不到的 那些在百度上搜不到的资源是在哪找的呢 就在这些强大的资源搜索网站呀 1 茶杯狐 茶杯狐 它的资源搜索功能很成熟 这里收集了海量的资源可以免费下载 只需要输入关键词 就可
  • 私网地址与Internet地址

    一 A B C三类地址 可用地址范围 备注 A类 1 0 0 1 126 255 255 254 B类 128 1 0 1 191 255 255 254 C类 192 0 1 1 223 255 255 254 D类 224 0 0 1
  • 关于verilog综合

    一 基本Verilog中的变量有线网类型和寄存器类型 线网型变量综合成wire 而寄存器可能综合成WIRE 锁存器和触发器 二 verilog语句结构到门级的映射1 连续性赋值 assign连续性赋值语句逻辑结构上就是将等式右边的驱动左边的
  • linux源代码.tar.xz解压

    刚开始学习linux内核 在linux内核官网https www kernel org 下载 我下载的版本是 linux 2 6 34 14 tar xz 由于我的linux中没有安装 xz的解压缩软件 需要下载 http download
  • linux dd命令小结

    为什么写本文 最近使用dd命令比较多 它是linux下功能强大的数据复制工具 这篇博文对它的使用做个小结 一来加深记忆 二来方便自己以后查阅 dd命令的功能 dd的主要功能是拷贝文件 默认从标准输入拷贝到标准输出 这意味dd可以在管道中使用
  • SpringBoot集成微信支付JSAPIV3保姆教程

    前言 最近为一个公众号h5商城接入了微信支付功能 查找资料过程中踩了很多坑 以此文章记录一下和大家分享 前期准备 公众号认证 微信支付功能需要开通企业号并进行资质认证 费用一年300 且需企业营业执照等信息 对公账户打款验证 登录微信公众平
  • 《人工智能算法图解》书籍分享(包邮送书)

    文章目录 人工智能介绍 书籍分享 抽奖包邮送书 人工智能介绍 人工智能算法是一种能够模拟人类智能行为的计算机算法 它通过分析和处理大量的数据 利用机器学习 深度学习和自然语言处理等技术 实现自主学习 推理和决策的能力 人工智能算法的发展经历
  • ​外包公司干了不到3个月,我离职了...(防坑指南)

    外包公司干了不到3个月 我离职了 当项目快要做完的时候 我就担心自己是不是要被 释放了 直到外包HR wx找我聊项目 我就不担心了 结果确实是要被 释放 从杭州到深圳 来的也突然 离职也有点突然 也是意料之中 本来想写 年终总结 结果现在要
  • Java五子棋

    提示 本人大二时的java大作业 当时没有学数据库 只是学到界面哪里 所以做出的条件有限 哈哈 看看就好 有帮助了 就拿走 不谢 Java五子棋 前言 主要就是涉及到java界面编程 实现Runable接口重写run方法 实现多线程 来控制
  • SQL中declare申明变量

    原文地址 http blog csdn net yanpingsz article details 5633660 在sql语句中添加变量 declare local variable data type 声明时需要指定变量的类型 可以使用
  • python定时运行,多进程

    可以通过另开一条线程 去专门做这件事情 py2代码如下 如果是py3请自行调整下语法 coding utf8 import threading import time 真正要执行的函数 def t1 print ok 每隔10秒钟执行 de
  • 五大车载操作(VOS)系统优劣对比,车载系统架构分析-QNX系统性能分析

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 声明 本文只用于个人学习交流 若不慎造成侵权 请及时联系我 立即予以改正 锋影 email 174176320 qq com 导读 车载操作
  • UART、TTL和RS232的区别

    UART TTL和RS232的区别 串行通信 UART TTL RS232 学习硬件的开始接触的就是串口 但是一直没搞懂UART TTL和RS232这些的关系 总感觉相互之间有所交叉 无法完全区分开 于是有了这篇博文 但是 这篇博文自我感觉
  • 分离轴定理(SAT):凸多边形相交检测

    引言 在计算机图形学 游戏开发 碰撞检测等领域 凸多边形相交检测是一个常见而重要的问题 为了快速准确地判断两个凸多边形是否相交 分离轴定理 Separating Axis Theorem 简称 SAT 成为了一种高效而可靠的算法 本文将深入
  • css里各个元素的书写顺序

    1 位置相关 position top left index float display 2 大小相关 width height margin padding 3 文字相关 font line height color letter spa
  • Python 怎么利用Python绘制二元高次隐函数的函数图像及其极值点——以某双核论文模型方程为例

    项目场景 几日前 在研究某双核期刊的某篇论文时 发现论文上的函数图像绘制得似乎有些不精确 原函数方程为 0 2045 y 2 3 4 y 3 2 x y 2 0 45 2 0 论文原文中函数图像如下图 问题描述 可以很明显地看出 极值点附近
  • Gof23设计模式之模板方法模式

    1 定义 定义一个操作中的算法骨架 而将算法的一些步骤延迟到子类中 使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤 2 结构 模板方法 Template Method 模式包含以下主要角色 抽象类 Abstract Clas