设计模式:模板方法模式

2023-10-26

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

事实上,模版方法是编程中一个经常用到的模式。先来看一个例子,某日,程序员A拿到一个任务:给定一个整数数组,把数组中的数由小到大排序,然后把排序之后的结果打印出来。经过分析之后,这个任务大体上可分为两部分,排序和打印,打印功能好实现,排序就有点麻烦了。但是A有办法,先把打印功能完成,排序功能另找人做。

abstract class AbstractSort {  
      
    /** 
     * 将数组array由小到大排序 
     * @param array 
     */  
    protected abstract void sort(int[] array);  
      
    public void showSortResult(int[] array){  
        this.sort(array);  
        System.out.print("排序结果:");  
        for (int i = 0; i < array.length; i++){  
            System.out.printf("%3s", array[i]);  
        }  
    }  
}  

写完后,A找到刚毕业入职不久的同事B说:有个任务,主要逻辑我已经写好了,你把剩下的逻辑实现一下吧。于是把AbstractSort类给B,让B写实现。B拿过来一看,太简单了,10分钟搞定,代码如下:

class ConcreteSort extends AbstractSort {  
  
    @Override  
    protected void sort(int[] array){  
        for(int i=0; i<array.length-1; i++){  
            selectSort(array, i);  
        }  
    }  
      
    private void selectSort(int[] array, int index) {  
        int MinValue = 32767; // 最小值变量  
        int indexMin = 0; // 最小值索引变量  
        int Temp; // 暂存变量  
        for (int i = index; i < array.length; i++) {  
            if (array[i] < MinValue){ // 找到最小值  
                MinValue = array[i]; // 储存最小值  
                indexMin = i;   
            }  
        }  
        Temp = array[index]; // 交换两数值  
        array[index] = array[indexMin];  
        array[indexMin] = Temp;  
    }  
}  

写好后交给A,A拿来一运行:

public class Client {
	public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 }; // 预设数据数组
	public static void main(String[] args){
		AbstractSort s = new ConcreteSort();
		s.showSortResult(a);
	}

}

排序结果:  0  1  3  4  5  7  9 10 12 32

运行正常。行了,任务完成。没错,这就是模版方法模式。大部分刚步入职场的毕业生应该都有类似B的经历。一个复杂的任务,由公司中的牛人们将主要的逻辑写好,然后把那些看上去比较简单的方法写成抽象的,交给其他的同事去开发。这种分工方式在编程人员水平层次比较明显的公司中经常用到。比如一个项目组,有架构师,高级工程师,初级工程师,则一般由架构师使用大量的接口、抽象类将整个系统的逻辑串起来,实现的编码则根据难度的不同分别交给高级工程师和初级工程师来完成。怎么样,是不是用到过模版方法模式?

模版方法模式的结构

模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:

  1. 抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
  2. 模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
  3. 钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。

(钩子方法,是对于抽象方法或者接口中定义的方法的一个空实现,在实际中的应用,比如说有一个接口,这个接口里有7个方法,而你只想用其中一个方法,那么这时,你可以写一个抽象类实现这个接口,在这个抽象类里将你要用的那个方法设置为abstract,其它方法进行空实现,然后你再继承这个抽象类,就不需要实现其它不用的方法,这就是钩子方法的作用。)

抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。

实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。

模版方法的优点及适用场景

容易扩展。一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。

便于维护。对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。

比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。

在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。

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

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

  • 2020最佳mac端app新鲜出炉!今年,你发现了哪些好软件?

    虽然2020年对于整个世界来说都是多舛的一年 但不管怎么说生活都在继续 而进入十二月之后 各大年度榜单也逐渐出现在了大家的视野里 今天为大家总结了12款2020年度最佳mac app 有了它们的加成 mac的使用体验更加流畅不说 生产力也能
  • C#调用带结构体指针的C Dll的方法

    在C 中调用C C 类的DLL的时候 有时候C的接口函数包含很多参数 而且有的时候这些参数有可能是个结构体 而且有可能是结构体指针 那么在C 到底该如何安全的调用这样的DLL接口函数呢 本文将详细介绍如何调用各种参数的方法 一 调用接口仅含
  • Flask电影网站项目

    1 开发环境搭建 1 1 Windows环境 下载Python 下载PyCharm 下载virtualenv 下载MySQL 可以安转一个数据库GUI 1 2 Linux环境 下载VMware Workstation Pro 下载ubunt
  • Redhat/CentOS Linux 进入单用户模式

    以 CentOS 7 9 和 Redhat 8 2 为例进行操作 因为CentOS是Redhat的发行版 所以同版本号界面和操作是一样的 CentOS 7 9 开机在 grub 引导界面时 按下 e 键进入编辑模式 找到 linux16 这
  • Ubuntu安装软件步骤

    Ubuntu安装软件步骤 sudo apt get update sudo apt get install flex bison gperfbuild essential curl zlib1g dev g multilib g 4 4 m
  • Source Insight 4.0 下载 安装 配置

    目录 下载地址 安装 打开 试用 导入工程 代码 1 新建一个项目 project 2 填充项目名及代码路径 3 这个直接点OK 4 导入项目文件 5 重建一下项目 6 打开项目文件 project Files 修改source insig
  • CS162 13-17 虚拟内存

    起源 为啥我们需要虚拟内存 需求是啥 可以给程序提供一个统一的视图 比如多个程序运行同一个代码段的话 同一个kernel 就可以直接共享 cpu眼里的虚拟内存 无限内存的假象 设计迭代过程 为啥这样设计 一个迭代过程 用上下界来做 缺点 还
  • Basic Level 1065 单身狗 (25分)

    题目 单身狗 是中文对于单身人士的一种爱称 本题请你从上万人的大型派对中找出落单的客人 以便给予特殊关爱 输入格式 输入第一行给出一个正整数 N 50 000 是已知夫妻 伴侣的对数 随后 N 行 每行给出一对夫妻 伴侣 为方便起见 每人对
  • cv2.error: OpenCV(4.6.0) :-1: error: (-5:Bad argument) in function ‘seamlessClone‘

    Can t parse p Sequence item with index 0 has a wrong type 1 软件环境 2 问题描述 3 解决方法 4 结果预览 1 软件环境 Windows10 教育版64位 Python 3 6
  • 函数式接口

    接口 package cn dali5 code01 函数式接口 有且仅有一个抽象方法的接口 可以有其他的方法 默认 静态 私有 函数式接口 适用于函数式编程场景的接口 Java中函数式编程的提现就是lambda表达式 所以函数式接口就是可

随机推荐

  • python子类定义报错:TypeError: __init__() missing 1 required positional argument: ‘prilege‘

    在学习 Python编程 从入门到实践 中类这一章节 其中子类的案例代码如下 class Car snip class Battery 一次模拟电动汽车电瓶的简单尝试 def init self battery size 70 初始化电瓶的
  • html5media使用api,html5中media(播放器)的api使用指南.pdf

    代码如下 HTML Audio API HTML5 Audio API HTML5 Audio API demo by target blank gt LearnShare Last update 2013 04 23 20 40 00 a
  • Python多线程、多进程和协程的实例讲解

    线程 进程和协程是什么 线程 进程和协程的详细概念解释和原理剖析不是本文的重点 本文重点讲述在Python中怎样实际使用这三种东西 参考 进程 线程 协程之概念理解 进程 Process 是计算机中的程序关于某数据集合上的一次运行活动 是系
  • WebUploader使用

    WebUploader用于文件的上传 文件上传过程为 网页中点击上传按钮 弹出选择文件窗口 并选择一个文件 在网页中显示选中的内容 给使用者一个反馈 点击上传按钮 文件开始上传 同时服务端开始接收文件 对于服务端而言 框架往往都有自己的接收
  • Jmeter(二十六) - 从入门到精通 - 搭建开源论坛JForum(详解教程)

    1 简介 今天这篇文章主要是给大家讲解一下 如何部署测试环境 这里宏哥部署一个开源测论坛 后边的文章中会用到这个论坛 并且也看到童鞋们在群里讨论如何在开发将测试包发给你以后 你如何快速地部署测试环境 这里就是简单的演示一下 应该具体项目灵活
  • 洛谷 P1085 不高兴的津津

    这个题目需要连续换行输入7组数据 并且对数据的最大值进行比较和提取 题目描述 津津上初中了 妈妈认为津津应该更加用功学习 所以津津除了上学之外 还要参加妈妈为她报名的各科复习班 另外每周妈妈还会送她去学习朗诵 舞蹈和钢琴 但是津津如果一天上
  • IDEA的配置JDK,Tomcat,Maven

    IDEA的配置JDK Tomcat Maven 先下载安装jdk 其中JDK为安装版 tomcat 和maven为非安装版 JDK安装完成后要设置3个坏境变量 tomcat和maven好像不设置也行 就下载下来解压就行了 maven最好还是
  • 小米android11账号补丁,小米10 MIUI11 解账户锁 可登小米账号 永不反锁 完美ROOT 解锁包...

    MIUI全机型有锁机账户锁刷机包 仅针对于有锁机用户使用 帮助已经购买到有锁机的用户 ROM版权归小米 官方所有 本人未持有任何版权 仅以分享形式发布 对ROM稳定性也不能做任何保证 如果你希望更好的系统 体验 我们非常建议购买正规渠道的小
  • 用Construct2开发一个小游戏(进阶)

    策划并用Construct2开发一个小游戏 进阶 游戏策划 楔子 Setting 公元2500年 与地球建交长达200之久的达克星球 Dark Star 单方面撕毁友好合约 对地球发起了进攻 面对源源不断的独眼怪大军 你踏入自己发明的 洋芋
  • MATLAB——读取多文件夹内文件并绘制图形(1)——逐行读取txt文件内字符串

    目录 1 添加路径 2 准备好图片名称和路径名称 3 读取txt文件中的字符串 1 添加路径 如果m文件和要读取的文件不在同一个路径下 需要借助下方代码将当前文件夹下的所有文件都包含进搜索路径中 addpath genpath F SaCo
  • Swin-Transformer

    原视频链接 https www bilibili com video BV1pL4y1v7jC spm id from 333 788 vd source f04f16dd6fd058b8328c67a3e064abd5 参考博文 2021
  • 哈夫曼编码设计(C)

    文章目录 前言 哈夫曼编码设计 总结 前言 大二 刚刚开始学数据结构与算法 写得不好 哈夫曼编码设计 现要求输入8个字符 a b c d e f g h 对应的权值 大于0的整数 然后设计哈夫曼编码实现输入对应8个字符组成的一串字符 字符串
  • centos 网络连接设置

    这里使用虚拟机 VirtualBox 来安装CentOS 6 3 32bit服务器版本 没有安装桌面 作为演示 所以全是命令操作 如何安装CentOS操作系统就不用我说的 虚拟机网络设置为桥接模式 Bridge 单独分配ip 不共享主机ip
  • 致命错误:Rdefines.h:没有那个文件或目录

    致命错误 Rdefines h 没有那个文件或目录 Rdefines h No such file or directory 关键词 CentOS 7 安装rpy2 pip3 install rpy2报错 python3 setup py
  • C#——字符串

    System String类 1 创建字符串 string s abcdefg 2 获取字符串长度 s Length 3 比较字符串是否一样 s abcd 4 字符串连接 s http s 5 使用类似索引器的语法来取得字符串中的某个字符
  • Android常见漏洞

    Android常见漏洞 漏洞名称 Log敏感信息泄露 漏洞描述 程序运行期间打印了用户的敏感信息 造成泄露 修改建议 建议禁止隐私信息的log 漏洞名称 web https校验错误忽略漏洞 漏洞描述 漏洞可导致中间人攻击 修改建议 建议不要
  • JAVA基础练习题

    1 生成两个1 10的随机数 分别作为两个数组的长度 2 向第一个数组中以循环键盘录入的方式添加元素 3 生成1 100之间的随机数 为第二个数组的每个元素赋值 4 将两个数组合并 为一个新的数组 5 去掉新数组的最大值和最小值 求平均值
  • vue之--使用TypeScript

    搭配 TypeScript 使用 Vue 像 TypeScript 这样的类型系统可以在编译时通过静态分析检测出很多常见错误 这减少了生产环境中的运行时错误 也让我们在重构大型项目的时候更有信心 通过 IDE 中基于类型的自动补全 Type
  • C++ 好用的日志库--spdlog

    背景 spdlog 是一个快速 异步的 header only 的 C 日志库 它提供了简单易用的 API 并具有高性能和可扩展性 下载和使用 下载 spdlog 库下载地址 github 链接 hello world 在使用时只需要 in
  • 设计模式:模板方法模式

    定义一个操作中算法的框架 而将一些步骤延迟到子类中 使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤 类图如下 事实上 模版方法是编程中一个经常用到的模式 先来看一个例子 某日 程序员A拿到一个任务 给定一个整数数组 把数组中的