Java 设计模式系列:模板方法模式

news2025/6/8 7:36:06

简介

模板方法模式是一种行为型设计模式,它定义一个操作中的算法骨架,将一些步骤推迟到子类中。模板方法模式使得子类可以不改变一个算法的结构,即可重定义该算法的某些特定步骤。

在模板方法模式中,抽象类中定义了一系列基本操作,这些操作是具体的也可以是抽象的,每一个基本操作对应算法的一个步骤。在子类中可以重定义或实现这些步骤,同时抽象类实现了一个模板方法,定义一个算法的框架。

模板方法模式通过封装不变部分,扩展可变部分,将特定步骤的具体实现与操作流程分离开来,实现了代码的复用和扩展,提高了代码质量和可维护性。同时,由于模板方法模式将具体实现由子类来完成,因此可以方便地扩展新的功能或变更实现方式,同时不影响模板方法本身。

然而,模板方法模式也存在一些缺点。由于每个算法都需要一个抽象类和具体子类来实现,因此在操作流程比较多时可能导致类的数量急剧增加,从而导致代码的复杂性提高。同时,由于模板方法和子类紧密相关,如果该模板方法需要修改,可能会涉及到多个子类的修改。

结构

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

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

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

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

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

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

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

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

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

案例实现

【例】炒菜

炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。类图如下:

在这里插入图片描述

代码如下:

public abstract class AbstractClass {
    
    public final void cookProcess() {
        //第一步:倒油
        this.pourOil();
        //第二步:热油
        this.heatOil();
        //第三步:倒蔬菜
        this.pourVegetable();
        //第四步:倒调味料
        this.pourSauce();
        //第五步:翻炒
        this.fry();
    }

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

    //第二步:热油是一样的,所以直接实现
    public void heatOil() {
        System.out.println("热油");
    }

    //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
    public abstract void pourVegetable();

    //第四步:倒调味料是不一样
    public abstract void pourSauce();


    //第五步:翻炒是一样的,所以直接实现
    public void fry(){
        System.out.println("炒啊炒啊炒到熟啊");
    }
}

public class ConcreteClass_BaoCai extends AbstractClass {

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

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }
}

public class ConcreteClass_CaiXin extends AbstractClass {
    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是菜心");
    }

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }
}

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

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

优缺点

优点:

  • 提高代码复用性

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

  • 实现了反向控制

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

缺点:

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

源码中的应用

JDK中

  1. java.io.InputStream:这是 Java 输入流的抽象类。它定义了一系列读取字节的方法,如read()read(byte[] b, int off, int len)。它的子类,如FileInputStreamByteArrayInputStream等,实现了这些抽象方法以提供不同的输入来源。

    https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/io/InputStream.java

  2. java.util.AbstractList:这是 Java 集合框架中 List 接口的抽象实现。它实现了 List 接口中的大部分方法,例如get(int index)size(),而add(int index, E element)remove(int index)等修改列表的方法则被定义为抽象,留给具体的子类实现。

    https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/AbstractList.java

  3. javax.servlet.http.HttpServlet:这是 Java Servlet API 中的一个关键类,用于处理 HTTP 请求。HttpServlet定义了doGet()doPost()等用于处理不同 HTTP 方法的抽象方法,开发人员可以通过扩展HttpServlet并覆盖这些方法来编写自定义的 HTTP 请求处理逻辑。

Spring中

  1. JdbcTemplateJdbcTemplate 是 Spring JDBC 模块中的一个核心类,它简化了 JDBC 编程。JdbcTemplate 使用了模板方法模式,定义了一组模板方法,如execute()query()update()等,这些方法定义了 JDBC 操作的通用流程,但将实际的 SQL 查询、参数设置等操作留给了回调接口或者 Lambda 表达式,使得用户可以根据需要进行定制。
  2. RestTemplate:在 Spring Web 模块中,RestTemplate 是一个用于访问 RESTful 服务的客户端类。它也使用了模板方法模式,定义了一组模板方法,如getForObject()postForObject()等,这些方法封装了 HTTP 请求的通用逻辑,但实际的 HTTP 请求发送和响应处理由具体的 HTTP 消息转换器等组件来实现。
  3. AbstractController:在 Spring MVC 中,AbstractController 是一个抽象控制器类,它定义了一些处理请求的模板方法,如handleRequestInternal()。开发者可以通过扩展AbstractController并实现这些模板方法来创建自定义的控制器,从而实现特定的请求处理逻辑。

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

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

相关文章

【Web】DASCTF 2023 0X401七月暑期挑战赛题解

目录 EzFlask MyPicDisk ez_cms ez_py 让俺看看401web题 EzFlask 进来直接给了源码 import uuidfrom flask import Flask, request, session from secret import black_list import jsonapp Flask(__name__) app.secret_key str(uuid.uuid4())def check(data):for i i…

数据库(3)

目录 11.那你知道什么是覆盖索引和回表吗? 12.什么是MVCC?说说MySQL实现MVCC的原理? 13.MySQL的锁的类型有哪些呢? 14.你们数据量级多大?分库分表是怎么做的? 15.分表后非分库字段sharding_key的查询怎…

OSCP靶场--ClamAV

OSCP靶场–ClamAV 考点 1.nmap扫描 ##┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC 192.168.153.42 -p- -Pn --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-13 10:01 EDT Nmap scan report for 192.168.153.42 Host is up (0.24s latency). N…

现在租一个服务器多少一个月?

现在租一个服务器多少一个月?优惠价格低至3.8元1个月,租用一个月云服务器收费价格表:阿里云和腾讯云2核2G3M服务器优惠价格61元一年,折合一个月5元,京东云轻量云主机5.8元一个月,华为云服务器优惠价格3.8元…

口型动画论文2:《基于语音驱动的表情动画设计与实现》

说明 本文是北京邮电大学的硕士毕业论文,作者是郭梦婷。由于是艺术硕士,所以本文没有罗列很多公式,而是从动画创作的角度来写如何根据语音设计动画人物的嘴型及表情。本文作者行文缜密、轻松,举得例子都是一些热播的动画和电影&a…

机器人坐标系转换之从世界坐标系到局部坐标系

三角函数实现 下面是代码c和python实现&#xff1a; #include <iostream> #include <cmath>struct Point {double x;double y; };class RobotCoordinateTransform { private:Point origin; // 局部坐标系的原点在世界坐标系中的坐标public:RobotCoordinateTransfo…

康耐视visionpro-CogBlobTool工具操作详细说明

CogBlobTool功能说明: 通过设置灰度值提取感兴趣区域,并分析所提取区域的面积、长宽等参数。 Cog BlobTool操作说明: .打开工具栏,双击或点击鼠标拖拽添加CogBlobTool工具 ②.添加输入图像:单击鼠标右键“链接到”或以连线拖拽的方式选择相应输入源 ③.极性: “白底黑点…

计算机毕业设计Python+Flask电商商品推荐系统 商品评论情感分析 商品可视化 商品爬虫 京东爬虫 淘宝爬虫 机器学习 深度学习 人工智能 知识图谱

一、选题背景与意义 1.国内外研究现状 国外研究现状&#xff1a; 亚马逊&#xff08;Amazon&#xff09;&#xff1a;作为全球最大的电商平台之一&#xff0c;亚马逊在数据挖掘和大数据方面具有丰富的经验。他们利用Spark等大数据技术&#xff0c;构建了一套完善的电商数据挖…

H2O-3机器学习平台源码编译的各种坑

H2O-3机器学习平台是一个非常适合非专业人士学习机器学习的平台&#xff0c;自带WebUI&#xff0c;效果还是蛮不错的&#xff0c;官方也提供了jar包&#xff0c;一条命令就能直接运行&#xff0c;非常方便&#xff0c;但最近有源码编译的需求&#xff0c;实际操作过程中&#x…

Unity打包出来的apk安装时提示应用程式与手机不兼容,无法安装应用程式

1、遇到的问题 * 2、解决办法 这是因为你在Unity中导出来的apk手机安装包是32位的&#xff0c;才导致上述问题发生&#xff0c;要解决这个办法&#xff0c;需要在Unity中导出64位的手机安装包。 32位跟64位的区别&#xff0c;以及如何区分打出来的手机安装包是否是32位或者是…

ssm046人事管理信息系统+jsp

人事管理信息系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本人事管理信息系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短…

中仕公考:三支一扶期满后有编制吗?

三支一扶两年的期限到达之后&#xff0c;会自动获得编制吗? 完成三支一扶项目的服务期限后&#xff0c;参与人员必须通过正式的考试才能获得编制&#xff0c;而并不是期满后自动获得编制。但是&#xff0c;三支一扶服务期满人员在参加公务员考试中可依照其身份享受加分的优惠…

Vue.js npm错误:transpileDependencies.map不是一个函数

这个错误通常是由于npm版本不兼容导致的。在旧版本的npm中&#xff0c;transpileDependencies是一个字符串数组&#xff0c;我们可以直接配置需要编译的依赖库。而在较新版本的npm中&#xff0c;transpileDependencies被改成了一个对象&#xff0c;并且需要使用map()方法来处理…

【C语言基础】:预处理详解(一)

文章目录 一、预定义符号二、#define定义常量三、#define定义宏四、带有副作用的宏参数五、宏替换的规则 一、预定义符号 在C语言中设置了许多的预定义符号&#xff0c;这些预定义符号是可以直接使用的&#xff0c;预定义符号也是在预处理阶段进行处理的。 常见的预定义符号&…

uniapp开发小程序手写板、签名、签字

可以使用这个插件进行操作 手写板-签名签字-lime-signature - DCloud 插件市场 但是目前这个插件没有vue3 setup Composition API的写法。所以对于此文档提供的可以直接使用,需要使用Composition API方式实现的,可以继续看。 因为Composition API方式,更加的简单、灵活,…

逆向案例二十三——某租逆向,总是有映射源文件怎么办以及分析webpack代码

网址&#xff1a;aHR0cHM6Ly93d3cubWFvbWFvenUuY29tLyMvYnVpbGQ 抓取数据包发现载荷以及数据都进行了加密&#xff1a; 定位方法一&#xff1a;直接搜decrypt(,进入js文件&#xff0c;可以发现就是直接AES的解密方法&#xff0c;打上断点&#xff0c; 下方的d是解密函数 现在有…

vscode配置c\c++及美化

文章目录 vscode配置c\c及美化1.安装vscode2.汉化3.安装c\c插件4.安装mingw5.配置mingw6. 运行c代码6.1 创建代码目录6.2 设置文件配置6.3 创建可执行任务&#xff1a;task.json6.4 编译执行6.5 再写其他代码6.6 运行多个c文件 7. 运行c文件8.调式代码8.1 创建launch.json8.2 修…

010、Python+fastapi,第一个后台管理项目走向第10步:ubutun 20.04下安装ngnix+mysql8+redis5环境

一、说明 先吐槽一下&#xff0c;ubuntu 界面还是不习惯&#xff0c;而且用的是云电脑&#xff0c;有些快捷键不好用&#xff0c;只能将就&#xff0c;谁叫我们穷呢&#xff1f; 正在思考怎么往后进行&#xff0c;突然发现没安装mysql 和redis&#xff0c;准备安装&#xff0…

shell 调用钉钉通知

使用场景&#xff1a;机器能访问互联网&#xff0c;运行时间任务后通知使用 钉钉建立单人群 手机操作&#xff0c;只能通过手机方式建立单人群 电脑端 2. 配置脚本 #!/bin/bash set -e## 上图中 access_token字段 TOKEN KEYWORDhello # 前文中设置的关键字 function call_…

Visual Studio code无法正常执行Executing task: pnpm run docs:dev

最近尝试调试一个开源的项目&#xff0c;发现cmd可以正常启动&#xff0c;但是在vs中会报错&#xff0c;报错内容如下 Executing task: pnpm run docs:dev pnpm : 无法加载文件 E:\XXXX\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 http…