《设计模式》模板方法模式

news2024/12/29 11:08:08

《设计模式》模板方法模式

定义

  • 模板方法模式又叫模板模式,在一个抽象类中公开定义了执行它的方法的模板,子类可以根据需要重写方法实现,但是调用将按照抽象类中定义的方式进行。
  • 模板方法模式相当于定义了一个操作中算法的骨架,具体的特定步骤的实现延迟到子类中去定义,使得子类可以不更改一个算法的结构,就可以重新定义算法的某些特定步骤。
  • 基本思想就是:算法只存在于父类中,容易修改。如果需要修改算法,只需要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。

模板方法模式包含的角色

  • 抽象类:负责给出一个算法的轮廓和骨架,它由一个模板方法和若干个基本方法组成。
  • 具体子类:实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

作为模板模式的组成角色,抽象类中的模板方法和基本方法又可以细分为

  • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
  • 基本方法:定义了实现算法的具体步骤,基本方法又可以分为三种:(1)抽象方法 (2)具体方法 (3)钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般的钩子方法是用于判断的逻辑方法,方法名为isXXX(),返回值类型为 boolean.

模板方法模式的注意事项

  • 优点:实现了代码的最大化复用,父类的模板方法和已经实现的某些步骤会被子类继承而直接使用。既统一了算法,也提供了很大的灵活性,父类的模板方法确保了算法的结构保持不变,同时子类提供部分步骤的实现。
  • 缺点:**每一个不同的实现都需要一个子类去实现,导致类的个数增加,使得系统更加庞大。**此外,父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,这也提高了代码阅读的难度。
  • 需要注意的是,一般的模板方法需要用 final 修饰,防止子类重写模板方法。
  • 模板方法模式主要用在:算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。

模板方法模式类图
在这里插入图片描述

案例背景

经常在家里做饭的同学都知道,炒菜的基本步骤就是:倒油—>热油—>放菜(也指肉)—>放调料—>翻炒等步骤,这应该是大多数炒菜的步骤了,就像一个模板一样,即使是第一次炒菜的同学只要按照这个模板步骤去做,也能大概做个能吃的菜了哈哈!当然,至于味道的合口程序,就看大家自己对菜的口味的把控。这个生活中的炒菜场景,就是模板方法模式的典型应用。

原理类图如下所示:
在这里插入图片描述

Cook 类:

public abstract class Cook {
	// 常量方法,不让子类去实现
    public final void cookProcess() {
        //第一步:倒油
        this.pourOil();
        //第二步:热油
        this.heatOil();
        //第三步:放菜
        this.pourThings();
        //第四步:放调料
        this.pourSauce();
        //第五步:翻炒
        this.fry();
    }

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

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

    // 取决于做的是什么菜就放什么东西
    public abstract void pourThings();

    // 根据不同菜的特点,放入不同的调料
    public abstract void pourSauce();

    public void fry() {
        System.out.println("翻炒");
    }
}

StewedMeat 类:

public class StewedMeat extends Cook{
    @Override
    public void pourThings() {
        System.out.println("放大肉");
    }

    @Override
    public void pourSauce() {
        System.out.println("放酱油、生抽、盐、糖");
    }
}

FryEggplant 类:

public class FryEggplant extends Cook{
    @Override
    public void pourThings() {
        System.out.println("放大茄子");
    }

    @Override
    public void pourSauce() {
        System.out.println("放酱油、糖、酒、盐、鸡粉、生粉、八角、蒜头");
    }
}

Client 类:

public class Client {
    public static void main(String[] args) {
        // 做红烧肉
        StewedMeat stewedMeat = new StewedMeat();
        stewedMeat.cookProcess();
        System.out.println("-----------------------------");
        // 做红烧茄子
        FryEggplant fryEggplant = new FryEggplant();
        fryEggplant.cookProcess();
    }
}

如果这时候我想做一个煎豆腐,除了食用油以外,不放任何调料的那种,因此可以省略放调料的步骤。但是,在炒菜的算法中固定了炒菜的步骤,该怎么办呢?此时,我们可以在抽象类中定义一个钩子方法,用于控制放调料的步骤是否需要。

具体的代码如下所示:

public abstract class Cook {
    public final void cookProcess() {
        //第一步:倒油
        this.pourOil();
        //第二步:热油
        this.heatOil();
        //第三步:放菜
        this.pourThings();
        if (isOpen()) {
            //第四步:放调料
            this.pourSauce();
        }
        //第五步:翻炒
        this.fry();
    }

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

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

    // 取决于做的是什么菜就放什么东西
    public abstract void pourThings();

    // 根据不同菜的特点,放入不同的调料
    public abstract void pourSauce();

    public void fry() {
        System.out.println("翻炒");
    }

    // 钩子方法
    public abstract boolean isOpen();
}

模板方法模式在 JDK 源码中的应用

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;
	}
}

InputStream 父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个索引位置,读取 len 个字节数据。而具体读取一个字节数据的细节,由继承 InputStream 的子类去实现。

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

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

相关文章

回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入多输出

回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入多输出 目录回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入多输出预测效果基本介绍程序设计往期精彩参考资料预测效果 基本介绍 MATLAB实现CNN-GRU卷积门控循环单元多输入多输出&#xff0c;运行环境Matlab2020及以上…

【国科大模式识别】第三次作业

【题目一】现有四个来自于两个类别的二维空间中的样本, 其中第一类的两个样本为 (1,4)T(1,4)^T(1,4)T 和 (2,3)T(2,3)^T(2,3)T, 第二类的两个样本为 (4,1)T(4,1)^T(4,1)T 和 (3,2)T(3,2)^T(3,2)T 。这里, 上标 TTT 表示向量转置。若采用规范化增广样本表示形式, 并假设初始的权…

权限问题的理解——Linux

这里是目录标题一、重定向二、 学Linux的意义三、shell命令的运行原理四、Linux权限管理1.Linux中具体用户的分类五、Linux文件相关的权限概念文件类型文件的权限文件的权限操作去掉权限加上权限八进制文件权限操作更改文件的拥有者和所属组六、目录的权限七、默认权限权限掩码…

树莓派项目归档

Flask Flask登录注册界面美化 Flask 修改路由 Flask 创建404json返回 返回虚拟温湿度 Flask-移植开发环境到VSCode-手机局域网访问测试 Flask AJAX 获取数据 Flask 将项目从win部署到树莓派 添加监控窗口 Flask 编写shell脚本快速启动服务 树莓派 树莓派4B Ubuntu MAT…

leetcode螺旋矩阵总结

螺旋矩阵题目&#xff1a; leetcode54&#xff0c;59&#xff0c;885&#xff0c;2326 leetcode54 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 输入&#xff1a;matrix [[1,2,3,4],[5,6,7,8],[9,10,11,12]] 输出&#xff1a;[…

MSTP技术中引入的必要性

目前&#xff0c;城域光传送网大量存在的是传统的SONET/SDH环网和简单的MSTP网络&#xff0c;对带宽的指配基本上是静态的&#xff0c;无法适应大量的突发性数据业务&#xff0c;需要大量的人工操作和维护&#xff0c;耗时耗力、容易出错。为了改变现状&#xff0c;人们不断在传…

第二章 Flink 环境部署

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 一、Flink架构 Flink 是一个分布式系统&#xff0c;需要有效分配和管理计算资源…

python-turtle画图

认识TurtleTurtle是一个渲染器基于底层图形编程结构(API)构建&#xff0c;主要用于场景的构建以及3D物体的绘制(3D游戏、虚拟场景等)Turtle是一个窗体程序Turtle是Python语言中的一个很流行的绘制图像的函数库&#xff0c;想象一个小海龟在一个横轴为x&#xff0c;纵轴为y的坐标…

时序数据库 TDengine 携手北京科技大学设计研究院,助力冶金工业智慧化

北京科技大学设计研究院有限公司作为北京科技大学全资产业化技术推广机构&#xff0c;从 2013 年开始在冶金、钢铁行业进行业务系统开发和实施&#xff0c;围绕先进材料、绿色低碳和智能制造不断深耕细作&#xff0c;持续创新。其拥有高效轧制与智能制造国家工程研究中心、国家…

DPDK工作原理和环境搭建

DPDK工作原理DPDK环境搭建编译DPDKDPDK工作原理DPDK实践之处理UDP数据总结DPDK环境搭建 工具准备&#xff1a;VMware、ubuntu16.04。 &#xff08;1&#xff09;VMware添加两个网卡。桥接网卡作为 DPDK 运行的网卡&#xff0c;NAT 网卡作为 ssh 连接的网卡。 &#xff08;2&…

后台交互—springboot+mybatis整合小程序(源码演示)

后台准备pom.xml<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM…

【案例实战】SpringBoot整合GRPC微服务远程通信

1.什么是GRPC GRPC是RPC框架中的一种&#xff0c;是一个高性能&#xff0c;开源和通用的RPC框架&#xff0c;基于Protobuf序列化协议开发&#xff0c;且支持众多开发语言。 面向服务端和协议端&#xff0c;基于http/2设计&#xff0c;带来诸如双向流&#xff0c;流控&#xff…

足球视频AI(三)——YOLOV7目标检测自训练模型

一、基础概念 YoloV7提供的yolov7-tiny.onnx 对于图像中包含较大尺寸的足球检测准确率高。 但在实际应用中&#xff0c;足球视频中的足球非常小&#xff0c;默认的模型难于满足实际的足球检测需求。 1.1 识别目标 1&#xff09;固定机位的视频中足球的逐帧识别 1.2 实现思…

邮箱2023系统

邮箱2023系统 前言 VMMail作为一款开源的邮件系统&#xff0c;目前已经发布到了10.0版本。 该版本在 GitHub上是免费的&#xff0c;且代码也是开源的&#xff0c;所以该程序不会对 GitHub上的所有用户造成任何影响。 由于 VMMail开发时采用了开源代码&#xff0c;并在 GitHub上…

区块链之bolt数据库持久化与基本功能完善

文章目录bolt数据库安装使用bolt进行持久化存储bolt持久化的基本步骤创世区块的持久化新增区块的持久化完善区块链基本功能创世区块创建增加区块遍历区块链链接&#xff1a; 区块链项目github地址项目目前进度&#xff1a;bolt数据库安装 bolt数据库介绍&#xff1a; bolt数据…

Vue3过渡动画实现

文章目录P14Vue3过渡&动画实现过渡动画的使用过渡CSS动画效果同时设置过渡和动画mode和appearanimate.cssgsapgsap实现数字变化认识列表的过渡列表过渡的移动动画列表的交错过渡案例P14Vue3过渡&动画实现 过渡动画的使用 <template><button click"isShow…

进入新组织项目经理如何快速提升自己的影响力?

我们在工作中&#xff0c;经常以“对事不对人”来体现他们的专业性&#xff0c;但是这点并不符合人性。更多时候对人不对事&#xff0c;反倒能提高问题的解决能力。项目经理会发现&#xff0c;很多事情的推进&#xff0c;都建立在和对方的信任的基础上&#xff0c;所以先成为对…

使用Qt开发的linux嵌入式设备监控、管理框架,监测嵌入式设备运行状态,执行远程shell,远程升级,与客户端进行文件传输

linux SPY 简介 使用Qt开发的linux嵌入式设备监控、管理框架 [客户端]&#xff1a;aes_tcp_lib 完整代码下载地址&#xff1a;使用Qt开发的linux嵌入式设备监控、管理框架 开发环境 ubuntu 20Qt 5.12Qt Creator 4.13.1 核心功能 监测嵌入式设备运行状态转发客户端消息,…

划重点!企业在采购管理中应避免的10个错误

一家企业的采购能力在很大程度上取决于其采购管理系统的有效性。当系统运行良好时&#xff0c;那么采购就会相当顺利。如果你使用的是一个低效的系统&#xff0c;那就会导致一大堆常见的采购问题。 无论采购错误的根本原因是什么&#xff0c;任其发展&#xff0c;最终会给企业…

【ZooKeeper】第二章 JavaAPI 操作

【ZooKeeper】第二章 JavaAPI 操作 文章目录【ZooKeeper】第二章 JavaAPI 操作一、Curator 简介二、Curator API1.建立连接2.创建节点3.查询节点4.修改节点5.删除节点6.Watch 事件监听三、分布式锁四、案例&#xff1a;12306售票一、Curator 简介 Curator 是 Apache ZooKeeper…