设计模式 14 模板模式

模板模式(Template Pattern)属于 行为型模式

在生活中常常会遇到这样的情况,做某一件事情,有些步骤是固定的,有些步骤的变化的。

比如去医院看病, 挂号排队这两个步骤是固定的,不管是什么病到了医院都得遵循这两个步骤;但是后续的 检查治疗这两个步骤是变化的,不同的病需要采用不同的检查方式,然后采取不同的治疗手段。

针对这一情况,在设计去医院看病这一程序时可以这样实现:定义一个抽象类,固定的步骤用普通方法实现,变化的步骤定义为抽象方法,由子类继承实现。这样就可以根据不同的子类来实现不同的变化步骤,这就是 模板模式

这里以去医院看病来介绍模板模式:

1、定义抽象疾病

/**
 * 疾病
 */
public abstract class Disease {

    /**
     * 治病
     */
    public void cure() {

        // 1、挂号
        registered();
        // 2、排队
        queue();
        // 3、检查
        check();
        // 4、治疗
        treat();
    }

    /**
     * 挂号
     */
    public void registered() {
        System.out.println("1、挂号");
    }

    /**
     * 排队
     */
    public void queue() {
        System.out.println("2、排队");
    }

    /**
     * 检查
     */
    public abstract void check();

    /**
     * 治疗
     */
    public abstract void treat();

}

2、定义具体疾病

感冒:

/**
 * 感冒
 */
public class Cold extends Disease {

    @Override
    public void check() {
        System.out.println("3、感冒检查:量体温");
    }

    @Override
    public void treat() {
        System.out.println("4、感冒开药:感冒灵");
    }
}

口腔溃疡:

/**
 * 口腔溃疡
 */
public class MouthUlcers extends Disease {

    @Override
    public void check() {
        System.out.println("3、口腔溃疡检查:看口腔");
    }

    @Override
    public void treat() {
        System.out.println("4、口腔溃疡开药:西瓜霜");
    }
}

3、调用

// 感冒
Disease cold = new Cold();
// 口腔溃疡
Disease mouthUlcers = new MouthUlcers();
// 治疗感冒
cold.cure();
// 治疗口腔溃疡
mouthUlcers.cure();

输出结果:

1、挂号
2、排队
3、感冒检查:量体温
4、感冒开药:感冒灵
1、挂号
2、排队
3、口腔溃疡检查:看口腔
4、口腔溃疡开药:西瓜霜

可以发现,在治疗感冒和口腔溃疡这两种疾病时,前两个步骤是一样的,只有后两个步骤是不同的,这样就实现了复用相同的步骤,后续再定义其他疾病时只需要继承 Disease 实现其抽象方法即可, 复用性扩展性都大大提高。

1、利用模板方法将相同处理逻辑的代码放到抽象父类中,提高了代码的 复用性

2、将不同的代码交由不同的子类实现,通过对子类的扩展增加新的行为,提高代码的 扩展性

1、每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

2、继承关系自身的缺点,如果父类添加新的抽象方法,所有子类都要添加该方法。

1、有多个子类共有的方法,且逻辑相同。

2、重要的、复杂的方法,可以考虑作为模板方法。

JUC 中的 AQS 判断是否发布方法 tryRelease 的实现

AbstractQueuedSynchronizer

/**
 * 锁释放操作
 */
public final boolean release(int arg) {
    // 调用 tryRelease 方法判断是否释放锁
    // 但是此方法并不是在 AQS 实现的,而是不同的锁自行实现
    // 因为 AQS 也不知道你这种类型的锁到底该怎么去解锁
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

ReentrantLock.Sync

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread()) {
        throw new IllegalMonitorStateException();
    }
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

AbstractQueuedSynchronizer 中没有实现 tryRelease ,而是在其子类 ReentrantLock.Sync 中实现。这就是对模板模式的典型应用。

为防止恶意操作,一般模板方法都会加上 final 关键词。

Original: https://www.cnblogs.com/codesail/p/16585419.html
Author: 程序航
Title: 设计模式 14 模板模式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/715005/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 传输中文的乱码的原因及解决方式(两次encodeURI())转码;

    .encodeURL函数主要是来对URI来做转码,它默认是采用的UTF-8的编码. . UTF-8编码的格式:一个汉字来三个字节构成,每一个字节会转换成16进制的编码,同时添加上%…

    技术杂谈 2023年6月1日
    087
  • Windows用户态程序高效排错–Heap和Stack[转帖]

    平坦内存空间中的层次结构:Heap和Stack 本小结主要介绍Heap相关的崩溃和内存泄漏,和如何使用pageheap来排错。首先介绍heap的原理,不同层面的内存分配,接下来通过…

    技术杂谈 2023年7月24日
    066
  • Oracle多租户架构之如何快速创建一个PDB

    Oracle自从12c版本开始引入多租户的架构,整个管理理念也发生了很大的变化。比如之前再小的业务只要选择了Oracle,DBA都会选择新建一套独立的数据库,因为传统的架构只能在s…

    技术杂谈 2023年5月31日
    092
  • git学习(一)-fork操作

    fork操作 对于某一个项目来说,如果自己不属于开发者中的一员,那么只能先fork别人的代码,然后将代码拉取到本地进行修改之后,再向原来的项目发起pull request。 for…

    技术杂谈 2023年7月24日
    090
  • Linux如何查看JDK的安装路径

    如何在一台Linux服务器上查找JDK的安装路径呢? 有那些方法可以查找定位JDK的安装路径?是否有一些局限性呢? 下面总结了一下如何查找JDK安装路径的方法. 1:echo $J…

    技术杂谈 2023年7月11日
    088
  • docker打包Python项目成镜像文件

    做实验时因为数据太大用到了学校的服务器平台,在平台进行训练的时候首先需要搭建环境,由于种种原因,只能自己用docker来打包镜像文件,自己做镜像。记录一下遇到的坑以及解决方法。 d…

    技术杂谈 2023年7月10日
    084
  • 分布式ID生成方案

    分布式ID策略 为什么要用分布式ID? 在我们业务数据量不大的时候,单库单表完全可以支撑现有业务,数据再大一点搞个 MySQL 主从同步读写分离也能对付。 但随着数据日渐增长,主从…

    技术杂谈 2023年6月21日
    0104
  • iOS_三角函数

    角度转弧度,弧度转角度 1、 三角函数double sin (double);正弦double cos (double);余弦double tan (double);正切2 、反三…

    技术杂谈 2023年5月30日
    085
  • Spring Ioc源码分析系列–容器实例化Bean的四种方法

    Spring Ioc源码分析系列–实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列–Bean实例化过程(二)在讲解到bean真正通…

    技术杂谈 2023年7月25日
    075
  • linux服务器端多进程代码-服务器/客户端一对多

    一、多进程服务器代码 #include #include #include #include<string.h> #include /* See NOTES */ #i…

    技术杂谈 2023年7月11日
    082
  • 聊聊foobar是什么?

    大一时看很多老外的文档,总是看到一个叫 foobar的词,当时倒不是纠结这个词到底是什么意思,因为看到这个词使用的场景大多是代码示例段、示例变量名等一些无意义的地方,猜也能猜到这个…

    技术杂谈 2023年7月11日
    070
  • 线上事故

    前言 前段时间,我们线上系统出现了一个事故:用户创建了商品,在商城的商品列表页看不到,也搜索不到。、 这个问题持续了大概半个小时,最后发现竟然是我的锅。 这个事情怎么说呢,完全是我…

    技术杂谈 2023年5月31日
    079
  • VS code 每次退出都要重新下载解决方案

    VS code 每次退出都要重新下载解决方案 打开文件-首选项-设置 在搜索栏输入Extensions: Auto Update 然后把所有打钩的取消 ,退出vs code 的时候…

    技术杂谈 2023年6月21日
    097
  • Java开发环境搭建

    ; ; Java开发环境搭建 JDK下载安装 配置环境变量 JDK目录介绍 Hello world及简单语法介绍 Notepad++安装及使用 如何卸载JDK 找到JDK安装目录 …

    技术杂谈 2023年6月21日
    0110
  • Linus:“我删除了Linux,因为它就是个垃圾”

    1月 25日, Linus Torvalds 在 Linux 的 GitHub 仓库中提交了一个恶作剧 README页面,其备注名为《delete linux because it…

    技术杂谈 2023年7月11日
    070
  • delete语句嵌套-mysql

    需求: 我需要从tableA之中找到name字段的Filter的记录,得到此记录的id,然后根据id删除tableA中的该条记录; — 但是我使用如下xql语句的时候delete…

    技术杂谈 2023年7月24日
    083
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球