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

模板方法模式是一种行为设计模式,允许在抽象类中定义算法框架,而将一些步骤延迟到子类中实现。文章通过代码示例展示了如何在Java中使用该模式,包括参数校验、资源评估、任务提交等固定步骤,子类则实现特定的操作。这种模式提高了代码复用性和扩展性,但也可能导致类的数量增加。
摘要由CSDN通过智能技术生成

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. 应用场景

  • 编排一个流程的固定步骤,实现某些步骤不变的部分,并将可变的步骤留给子类来实现,使得子类在步骤固定的情况下进行功能的不同实现和拓展
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值