【设计模式】Java设计模式——模板方法模式(Template Pattern)

news2024/9/26 1:25:06

文章目录

  • 1. 介绍
      • 1.1 定义
      • 1.2 作用
  • 2. 模式结构
      • 2.1 UML类图
      • 2.2 模式组成
  • 3. 代码实例
      • 3.1 背景
      • 3.2 应用
  • 4. 优点
  • 5. 缺点
  • 6. 应用场景

1. 介绍

1.1 定义

  • 模板方法模式(Template Pattern),又叫模板模式,它属于行为型模式
  • 模板方法模式定义一个模板结构,将具体内容延迟到子类去实现

1.2 作用

  • 使得子类可以在不改变一个模板的结构的前提下重新定义该模板的某些特定步骤

2. 模式结构

2.1 UML类图

在这里插入图片描述

2.2 模式组成

  • 模板方法(Template Method):模板方法定义了模板的特定步骤
  • 抽象方法(Abstract Method):抽象方法由抽象类声明,由其子类实现,使用abstract关键字标识
  • 具体方法(Concrete Method):具体方法由抽象类声明并实现,子类不可修改,使用final关键字标识
  • 钩子方法(Hook Method):钩子方法由抽象类声明,子类可以重写

3. 代码实例

3.1 背景

申请虚拟机需要分配ip,网卡,磁盘等,闲置时需要进行删除,每个操作的请求体各不相同,但是流程是一致的,比如参数校验,资源评估,生成任务id,提交任务等,这个时候定义一个模板类相当合适。

3.2 应用

代码主要为了说明模板方法模式的大致用法,非常简化,仅供参考

  • 步骤1 定义request类(公共参数可以抽成父类)

    public class AbstractVmRequest {
    
        /**
         * create/delete
         */
        private String action;
    
        private String operator;
    
        private String jobId;
    }
    
    public class VmIpRequest extends AbstractVmRequest {
    
        private List<CreateIpVO> createIpVOList;
    
        private List<DeleteIpVO> deleteIpVOList;
    }
    
    public class VmVolumeRequest extends AbstractVmRequest {
    
        private List<CreateVolumeVO> createVolumeVOList;
    
        private List<DeleteVolumeVO> deleteVolumeVOList;
    }
    
  • 步骤2 定义抽象模板类

    public abstract class AbstractVmRegister {
    
        public final String VmRegister(AbstractVmRequest request) throws Exception {
            // 参数校验
            verifyParameter(request);
    
            // 资源评估
            evaluateResource(request);
    
            // 生成任务id
            String jobId = generateJobId(request);
    
            // 提交并执行任务
            submitVmJob(request);
            return jobId;
        }
    
        // 抽象方法,由子类实现
        protected abstract void verifyParameter(AbstractVmRequest request) throws Exception;
    
        // 钩子方法,父类已实现,子类也可以重写
        protected void evaluateResource(AbstractVmRequest request) {
            // 当前资源充足,不进行资源评估
            System.out.println("skip evaluate resource");
        }
    
        // 具体方法,父类已实现,子类无需实现
        final String generateJobId(AbstractVmRequest request) {
            String jobId = UUID.randomUUID().toString();
            request.setJobId(jobId);
            return jobId;
        }
    
        // 抽象方法,由子类实现
        protected abstract void submitVmJob(AbstractVmRequest request);
    }
    
  • 步骤3 定义实现类-ip

    public class VmIpCreateRegister extends AbstractVmRegister {
    
        @Override
        protected void verifyParameter(AbstractVmRequest request) throws Exception {
            VmIpRequest vmIpRequest;
            if (request instanceof VmIpRequest) {
                vmIpRequest = (VmIpRequest) request;
            } else {
                throw new Exception("The bean type does not support ip create");
            }
            if (CollectionUtils.isEmpty(vmIpRequest.getCreateIpVOList())) {
                throw new Exception("createIpVOList can not be empty");
            }
        }
    
        @Override
        protected void submitVmJob(AbstractVmRequest request) {
            // 调用service方法执行操作
            // ipService.execute()
            System.out.println(String.format("submit ip create job, jobId: %s", request.getJobId()));
        }
    }
    
  • 步骤4 定义实现类-volume

    public class VmVolumeCreateRegister extends AbstractVmRegister {
    
        @Override
        protected void verifyParameter(AbstractVmRequest request) throws Exception {
            VmVolumeRequest vmVolumeRequest;
            if (request instanceof VmVolumeRequest) {
                vmVolumeRequest = (VmVolumeRequest) request;
            } else {
                throw new Exception("The bean type does not support volume create");
            }
            if (CollectionUtils.isEmpty(vmVolumeRequest.getCreateVolumeVOList())) {
                throw new Exception("createVolumeVOList can not be empty");
            }
        }
    
        @Override
        protected void submitVmJob(AbstractVmRequest request) {
            // 调用service方法执行操作
            // volumeService.execute()
            System.out.println(String.format("submit volume create job, jobId: %s", request.getJobId()));
        }
    }
    
  • 外部调用(这边推荐使用策略模式,提前将实现类放在map里,调用的时候直接通过map获取实现类)

    public static void main(String[] args) throws Exception {
    
            // 填充参数模拟api调用
            VmVolumeRequest vmVolumeRequest = new VmVolumeRequest();
            // action可以写成枚举类
            vmVolumeRequest.setAction("create");
            vmVolumeRequest.setOperator("DustHeart");
            vmVolumeRequest.setCreateVolumeVOList(Collections.singletonList(new CreateVolumeVO()));
    
            VmVolumeCreateRegister vmVolumeCreateRegister = new VmVolumeCreateRegister();
            String jobId = vmVolumeCreateRegister.VmRegister(vmVolumeRequest);
            System.out.println(jobId);
        }
    

4. 优点

  • 提高代码复用性,将相同处理逻辑的代码放在抽象父类中
  • 提高了拓展性,子类实现抽象父类的某些细节,有助于模板父类的扩展
  • 符合开闭原则,通过一个父类调用子类实现的操作,可以通过子类扩展增加新的行为

5. 缺点

  • 引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,系统会更加庞大
  • 模板方法主要通过继承实现,如果父类增加新的抽象方法,所有的子类都要修改一遍

6. 应用场景

  • 编排一个流程的固定步骤,实现某些步骤不变的部分,并将可变的步骤留给子类来实现,使得子类在步骤固定的情况下进行功能的不同实现和拓展

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

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

相关文章

Apikit 自学日记:版本管理

功能入口&#xff1a;API管理应用 / 选中某个项目 / 项目管理菜单 / 项目版本管理 项目版本管理功能模块提供对项目级别的版本管理&#xff0c;可新增、删除、对比项目级版本。在创建项目版本号的时候会对整个项目的部分模块数据进行快照保存。可用于每次迭代发布打全局版本号…

ESP32设备驱动-TMF8801激光测距传感器驱动

TMF8801激光测距传感器驱动 文章目录 TMF8801激光测距传感器驱动1、TMF8801介绍2、硬件准备3、软件准备4、驱动实现1、TMF8801介绍 TMF8801 是一款真正的直接飞行时间 (ToF) 传感器系统,采用单一模块化封装,通过亚纳秒光脉冲和抗锯齿“秒表”方法测量往返时间,提供高精度深度…

流量分析工具wireshark-学习笔记

&#xff08;一&#xff09;wireshark工具 1、wireshark工具简介 Wireshark是一种开源网络分析工具&#xff0c;它可以让你在计算机网络上捕获和查看数据包&#xff0c;并能帮助你深入了解网络的运行和协议的实现。它可以捕获不同类型的流量&#xff0c;包括以太网、Wi-Fi、TC…

【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 开篇 在现代Web开发中&#xff0c;异步请求已经成为了必不可少的一部分。然而&#xff0c;…

ISP之图像降分辨率

1、图像缩放背景 图像的放大、缩小(简称缩放)是图像处理的一种处理方法。所谓图像缩放是指图像分辨率的改变&#xff0c;它在图像显示、传输、图像分析以及动画制作、电影合成、甚至医学图像处理中都有着相当广泛的应用。比如要在1024 X 768 分辨率的显示器上全屏显示800 X 60…

8.2 电压比较器(2)

五、集成电压比较器 1、集成电压比较器的主要特点和分类 电压比较器可将模拟信号转换成二值信号&#xff0c;即只有高电平和低电平两种状态的离散信号。因此&#xff0c;可用电压比较器作为模拟电路和数字电路的接口电路。集成电压比较器虽然比集成运放的开环增益低&#xff…

强化学习从基础到进阶-案例与实践[6]:演员-评论员算法(advantage actor-critic,A2C),异步A2C、与生成对抗网络的联系等详解

【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧&#xff08;调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍&#xff1a;【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧…

Arcmap读取nc文件并导出为tif格式

Arcmap读取nc文件并导出为tif格式 前言操作步骤 前言 在使用某一降水数据的时候&#xff0c;发现直接把nc格式的数据拖进Arcmap&#xff0c;查看属性表的时候是空的&#xff0c;点击图上的信息也只会显示一个值&#xff0c;但这个nc数据应该是有很多个值的&#xff08;我的数据…

Kubernetes - adm搭建 · 保姆级教程

master&#xff08;2C/4G&#xff0c;cpu核心数要求大于2&#xff09; 192.168.179.25 docker、kubeadm、kubelet、kubectl、flannel node01&#xff08;2C/2G&#xff09; 192.168.179.26 docker、kubeadm、kubelet、kubectl…

【JavaScript】JavaScript中的nodeName、nodeType、nodeValue区别

文章目录 JavaScript中的nodeName、nodeType、nodeValue区别(一)nodeName(二)nodeValue(三)nodeType JS代码demo JavaScript中的nodeName、nodeType、nodeValue区别 (一)nodeName https://www.w3schools.cn/jsref/prop_node_nodename.html 元素节点的 nodeName是标签名称 属性…

ffmpeg windows编译及调试完整版

目录 编译 基础环境准备 依赖环境安装 依赖库安装 X264 fdk-aac X265 ffmpeg-4.3.6 调试 基础项目环境搭建 VS2019项目创建 VS2019项目代码 vs2019配置 VS2019调试 编译 基础环境准备 1、安装vs2019环境 2、安装msys2工具 3、开始菜单启动x86 Native Tools Comm…

从0到1精通自动化测试,pytest自动化测试框架,fixture之autouse=True(十二)

一、前言 平常写自动化用例会写一些前置的fixture操作&#xff0c;用例需要用到就直接传该函数的参数名称就行了。当用例很多的时候&#xff0c;每次都传这个参数&#xff0c;会比较麻烦 fixture里面有个参数autouse&#xff0c;默认是Fasle没开启的&#xff0c;可以设置为Tr…

diffusion model(一)DDPM技术小结 (denoising diffusion probabilistic)

DDPM技术小结 (denoising diffusion probabilistic) 1 从直觉上理解DDPM 在详细推到公式之前&#xff0c;我们先从直觉上理解一下什么是扩散 对于常规的生成模型&#xff0c;如GAN&#xff0c;VAE&#xff0c;它直接从噪声数据生成图像&#xff0c;我们不妨记噪声数据为 z z…

RTX 4060跑分出炉,加量还降价真良心了?

RTX 40 系真正意义上主流平民级显卡 4060 桌面版已确认于本月 29 日推出。 相较于原定的 7 月中旬上市提前了半个月左右&#xff0c;国内售价 2399 元&#xff08;比 RTX 3060 首发低 100 元&#xff09;。 从这样的「早产」操作能看出&#xff0c;RTX 40 系显卡拉胯销量表现确…

java并发编程 2:java线程基础知识

目录 创建和运行线程查看进程线程线程运行原理常见方法了解start与runsleep与yield线程优先级joininterrupt不推荐使用的方法 主线程与守护线程线程状态操作系统中的线程状态java中的线程状态 创建和运行线程 方法一: 直接使用 Thread public class CreateThread01 {public s…

使用U盘安装Centos7全流程分享

文章目录 1、下载 centos7 的镜像2、下载老白菜3、插入U盘4、将U盘插入要刷机的电脑中5、获取U盘的启动地址6、正式配置重启7、进入安装界面了&#xff0c;现在就容易7.1 选择中文7.2 点击安装位置&#xff0c;分配磁盘7.3 配置网络和主机7.4 选择开始安装&#xff0c;并配置账…

【第1集】odoo16开发环境搭建

因为博主使用Mac作为开发电脑&#xff0c;因此都以Mac为主。同时本文odoo使用的是16版本&#xff0c;采用python源码进行安装&#xff0c;如需要二进制安装同学&#xff0c;后续有条件可能会出这方面的搭建指导。本文包含四个部分&#xff0c;分别为数据库安装&#xff0c;系统…

C++ bool 类型

文章目录 一. bool 类型二. 三目运算符 一. bool 类型 在 C 中&#xff0c;bool 类型用于表示逻辑值&#xff0c;它只有两个可能的取值&#xff1a;true&#xff08;真&#xff09;和 false&#xff08;假&#xff09;。bool 类型常用于条件判断和布尔运算中。 C 标准要求 bo…

Cooike Session

1 会话技术 1.1 会话管理概述 1.1.1 什么是会话 这里的会话&#xff0c;指的是web开发中的一次通话过程&#xff0c;当打开浏览器&#xff0c;访问网站地址后&#xff0c;会话开始&#xff0c;当关闭浏览器&#xff08;或者到了过期时间&#xff09;&#xff0c;会话结束。 …

UE5 录制透明png序列帧

以下是在 Unreal Engine 5 中录制透明 PNG 序列帧的详细步骤&#xff1a; 步骤1&#xff1a;创建一个场景 步骤2&#xff1a;打开序列录制器 在 Unreal Engine 5 中&#xff0c;首先需要打开序列录制器。你可以通过点击顶部菜单栏的 窗口 > 开发人员工具 > 序列录制器 …