博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
折腾Java设计模式之模板方法模式
阅读量:5160 次
发布时间:2019-06-13

本文共 5737 字,大约阅读时间需要 19 分钟。

博客原文地址:

模板方法模式

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

翻译过来就是,把算法的框架定义好,可以将某些步抽象出来放到子类去实现。模板方法允许子类在不改变算法框架的情况下重新实现算法的某些步骤。

模板方法模式UML图

UML图

UML

抽象类AbstractClass定义了算法框架templateMethod()方法,其中有2个方法primitve1()primitve2()被抽象出来,子类SubClass1继承了抽象类AbstractClass,从而实现了primitve1()primitve2()

模板方法模式角色

抽象类(AbstractClass): 定义了算法核心框架,同时把局部的算法行为封装成步骤,让子类去实现。

子类(SubClass): 继承了抽象类,实现抽象类中的抽象方法,具体实现了算法部分逻辑。

模板方法模式源码示例

源码地址:

抽象方法

先定义抽象类,抽象类AbstractProcessor中核心算法handle方法中大体分3部,第一先校验参数具体怎么校验放在子类中实现,第二获取结果也放在子类实现,第三获取结果后的操作也放在子类实现。

@Slf4jpublic abstract class AbstractProcessor

{ /** * 逻辑处理 * * @param request * @return */ public R handle(P request) { // 1.校验参数 log.info("开始处理, 请求参数={}", request); validRequest(request); // 2.获取结果 R response = getResponse(request); log.info("获取结果, 响应结果={}", response); // 3.结果之后的处理 afterHandle(response); return response; } /** * 结果之后的处理 可以更新其他业务或者处理缓存 * * @param response */ protected abstract void afterHandle(R response); /** * 校验请求参数 * * @param request */ protected void validRequest(P request) { if (Objects.isNull(request.getToken())) { throw new RuntimeException("token不能为空"); } if (Objects.isNull(request.getVersion())) { throw new RuntimeException("version不能为空"); } validRequestParam(request); } /** * 校验请求真正的参数 * @param request */ protected abstract void validRequestParam(P request); /** * 获取到结果 * @param request * @return */ protected abstract R getResponse(P request);}

基本请求

@Data@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class Request {     private String version;     private String token;}

基本响应

@Data@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class Response {     private String msg;     private int code;     private boolean success;}

子类实现

第一个子类实现

@Slf4jpublic class OneProcessor extends AbstractProcessor
{ public OneProcessor() { ProcessorFactory.putProcess("two", this); } @Override protected void afterHandle(OneResponse response) { log.info("处理One结果: {}", response.getOne()); } @Override protected void validRequestParam(OneRequest request) { log.info("校验one参数...省略......"); } @Override protected OneResponse getResponse(OneRequest request) { String name = request.getName(); return OneResponse.builder() .one(name + "one") .success(true) .code(0) .msg("成功") .build(); }}

第一个子类的请求

@Data@ToString(callSuper = true)@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class OneRequest extends Request {    private String name;    @Builder.Default    private int a = 0;}

第一个子类的响应

@Data@ToString(callSuper = true)@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class OneResponse extends Response {    private String one;}

第二个子类实现

@Slf4jpublic class TwoProcessor extends AbstractProcessor
{ public TwoProcessor() { ProcessorFactory.putProcess("two", this); } @Override protected void afterHandle(TwoResponse response) { log.info("处理结果TWO, {}", response); } @Override protected void validRequestParam(TwoRequest request) { log.info("校验TWO参数...省略......"); } @Override protected TwoResponse getResponse(TwoRequest request) { Long id = request.getId(); return TwoResponse.builder() .two("id为"+id) .success(true) .code(0) .msg("成功") .build(); }}

第二个子类的请求

@Data@ToString(callSuper = true)@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class TwoRequest extends Request {    private Long id;}

第二个子类的响应

@Data@ToString(callSuper = true)@SuperBuilder@NoArgsConstructor@AllArgsConstructorpublic class TwoResponse extends Response {    private String two;}

扩展为工厂

有的时候我们定义的子类在Spring容器的时候由Spring定义好后,我们其实可以借用工厂模式方法,在子类初始化的时候就把子类放置在ProcessorFactory中,后续只需要根据key从中拿取即可,实际项目中用这种方式还是比较多的。

public class ProcessorFactory {    private static Map
factories = new HashMap(); public static void putProcess(String key, AbstractProcessor process) { factories.put(key, process); } public static AbstractProcessor selectProcess(String key) { return factories.get(key); }}

执行程序

@Slf4jpublic class TemplateMethodApplication {    public static void main(String[] args) {        OneRequest oneRequest = OneRequest.builder()                .version("2312312")                .token("23423")                .name("张三")                .build();        new OneProcessor().handle(oneRequest);        log.info("--------------------------");        TwoRequest twoRequest = TwoRequest.builder()                .version("2312312")                .token("23423")                .id(23456L)                .build();        new TwoProcessor().handle(twoRequest);    }}

结果

image-20190326112956730

总体上来讲,抽象类中定义了算法的框架,然后把部分算法步骤抽象出来供子类实现,有的时候有些方法只有个别子类会去实现,我们可以在抽象类中实现为空实现,在有需要的子类中我们可以覆盖抽象类的实现,这样避免了所有的子类都去实现,其实不关心的话都是空实现了。本示例用到了lombok@SuperBuilder特性,可能在下载完完整的代码后会出现编译错误,这是因为Lombok的插件暂时还不支持@SuperBuilder

模板方法模式总结

模板方法经常和其他模式混合使用,比如工厂、策略等等。其实在Spring中大量使用了模板方法模式,其实也不光在Spring中,像平时jdbcTemplate或者RedisTemplate,像这种带有Template的。

优点 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。

缺点 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

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

参考

欢迎关注我的微信公众号

微信公众号

转载于:https://www.cnblogs.com/damonchow/p/10634550.html

你可能感兴趣的文章
Android开发技术周报 Issue#80
查看>>
hadoop2.2.0+hive-0.10.0完全分布式安装方法
查看>>
django知识点总结
查看>>
C++ STL stack、queue和vector的使用
查看>>
使用Reporting Services时遇到的小问题
查看>>
约瑟夫问题
查看>>
Arduino 报错总结
查看>>
树莓派Android Things物联网开发:树莓派GPIO引脚图
查看>>
矩阵快速幂---BestCoder Round#8 1002
查看>>
如何将应用完美迁移至Android P版本
查看>>
【转】清空mysql一个库中的所有表的数据
查看>>
基于wxPython的python代码统计工具
查看>>
淘宝JAVA中间件Diamond详解(一)---简介&快速使用
查看>>
Hadoop HBase概念学习系列之HBase里的宽表设计概念(表设计)(二十七)
查看>>
Kettle学习系列之Kettle能做什么?(三)
查看>>
Day03:Selenium,BeautifulSoup4
查看>>
awk变量
查看>>
mysql_对于DQL 的简单举例
查看>>
35. Search Insert Position(C++)
查看>>
[毕业生的商业软件开发之路]C#异常处理
查看>>