Java设计模式之模板方法详解

 更新时间:2022年07月26日 15:13:05   作者:kaico2018  
模板方法的概念:定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

概念

模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术,没有关联关系。因此,在模板方法模式的类结构图中,只有继承关系。

核心设计要点

AbstractClass:抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现。

ConcreteClass:实现实现父类所定义的一个或多个抽象方法。。

优缺点

优点

  • 利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
  • 将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
  • 把不变的行为写在父类.上,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则。

缺点

类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加,复杂性增加。类数量的增加,间接地增加了系统实现的复杂度。继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一-遍。

应用场景

  • 父类视角:一次性实现一个算法不变的部分,并将可变部分留给子类实现;
  • 子类视角:各个子类中,公共部分被提取出来,集中到一个公共的父类中,避免代码重复;

模板方法模式的目的是让子类可以扩展或具体实现固定方法的某个具体的步骤;对于模板来说,是一套固定的算法 ,通过子类可以扩展固定算法中某些算法步骤。

模板方法和策略模式的区别

策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。还有一种模

式也是关注对算法的封装一模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类

Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主

体则是封装到了封装类Context中,抽象策略Strategy一般是一个接口, 目的只是为了定义规范,里面一般不包含逻辑。其实,这只是通用实现,而在实际编程中,因为各个具体策略实现类之间难免存在–些相同的逻辑,为了避免重复的代码,我们常常使用抽象类来担任Strategy的角色,在里面封装公共的代码,因此,在很多应用的场景中,在策略模式中- -般会看到模版方法模式的影子。

代码案例

模版方法抽象类

@Slf4j
public abstract class AbstractPayCallbackTemplate {
    /**
     * 异步回调业务
     *
     * @return
     */
    public String asyncCallBack() {
        // 1. 支付回调验证参数
        Map<String, String> verifySignatureMap = verifySignature();
        // 2. 参数验证成功,写入日志中..
        payLog(verifySignatureMap);
        String analysisCode = verifySignatureMap.get("analysisCode");
        if (!analysisCode.equals("200")) {
            return resultFail();
        }
        // 3. 执行回调异步相关逻辑
        return asyncService(verifySignatureMap);
    }
    /**
     * 支付回调验证参数
     *
     * @return
     */
    protected abstract Map<String, String> verifySignature();
    /**
     * 使用多线程异步写入日志
     *
     * @param verifySignatureMap
     */
    @Async
    void payLog(Map<String, String> verifySignatureMap) {
        log.info(">>>>>>>>>>第二步 写入payLog........");
    }
    /**
     * 每个子类需要实现 实现业务解析操作
     *
     * @return
     */
    protected abstract String asyncService(Map<String, String> verifySignatureMap);
    /**
     * 异步返回结果..
     *
     * @return
     */
    protected abstract String resultSuccess();
    /**
     * 异步返回失败
     *
     * @return
     */
    protected abstract String resultFail();
}

具体实现模版类

@Log4j2
public class AliPayCallbackTemplate extends AbstractPayCallbackTemplate {
    @Override
    protected Map<String, String> verifySignature() {
        //>>>>假设一下为银联回调报文>>>>>>>>>>>>>>>>
        log.info(">>>>>第一步 解析支付宝据报文.....verifySignature()");
        Map<String, String> verifySignature = new HashMap<>();
        verifySignature.put("price", "1399");
        verifySignature.put("orderDes", "充值永久会员");
        // 支付状态为1表示为成功....
        verifySignature.put("aliPayMentStatus", "1");
        verifySignature.put("aliPayOrderNumber", "201910101011");
        // 解析报文是否成功 200 为成功..
        verifySignature.put("analysisCode", "200");
        return verifySignature;
    }
    @Override
    protected String asyncService(Map<String, String> verifySignatureMap) {
        log.info(">>>>>第三步asyncService()verifySignatureMap:{}", verifySignatureMap);
        String paymentStatus = verifySignatureMap.get("aliPayMentStatus");
        if (paymentStatus.equals("1")) {
            String aliPayOrderNumber = verifySignatureMap.get("aliPayOrderNumber");
            log.info(">>>>orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付...");
        }
        return resultSuccess();
    }
    @Override
    protected String resultSuccess() {
        return "ok";
    }
    @Override
    protected String resultFail() {
        return "fail";
    }
}
@Slf4j
public class UnionPayCallbackTemplate extends AbstractPayCallbackTemplate {
    @Override
    protected Map<String, String> verifySignature() {
        //>>>>假设一下为银联回调报文>>>>>>>>>>>>>>>>
        log.info(">>>>>第一步 解析银联数据报文.....verifySignature()");
        Map<String, String> verifySignature = new HashMap<>();
        verifySignature.put("price", "1399");
        verifySignature.put("orderDes", "充值永久会员");
        // 支付状态为1表示为成功....
        verifySignature.put("paymentStatus", "1");
        verifySignature.put("orderNumber", "201910101011");
        // 解析报文是否成功 200 为成功..
        verifySignature.put("analysisCode", "200");
        return verifySignature;
    }
    @Override
    protected String asyncService(Map<String, String> verifySignatureMap) {
        log.info(">>>>>第三步asyncService()verifySignatureMap:{}", verifySignatureMap);
        String paymentStatus = verifySignatureMap.get("paymentStatus");
        if (paymentStatus.equals("1")) {
            String orderNumber = verifySignatureMap.get("orderNumber");
            log.info(">>>>orderNumber:{orderNumber},已经支付成功 修改订单状态为已经支付...");
        }
        return resultSuccess();
    }
    @Override
    protected String resultSuccess() {
        return "success";
    }
    @Override
    protected String resultFail() {
        return "fail";
    }
}

工厂模式获取模版

public class TemplateFactory {
    private final static Map<String, AbstractPayCallbackTemplate> templateMap = new ConcurrentHashMap<>();
    static {
        templateMap.put("aliPay", new AliPayCallbackTemplate());
        templateMap.put("unionPay", new UnionPayCallbackTemplate());
    }
    public static AbstractPayCallbackTemplate getPayCallbackTemplate(String templateId) {
        AbstractPayCallbackTemplate payCallbackTemplate = (AbstractPayCallbackTemplate) templateMap.get(templateId);
        return payCallbackTemplate;
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        AbstractPayCallbackTemplate aliPay = TemplateFactory.getPayCallbackTemplate("aliPay");
        String s = aliPay.asyncCallBack();
        System.out.println(s);
    }
}

到此这篇关于Java设计模式之模板方法详解的文章就介绍到这了,更多相关Java模板方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Eclipse远程debug的步骤与注意事项

    Eclipse远程debug的步骤与注意事项

    今天小编就为大家分享一篇关于Eclipse远程debug的步骤与注意事项,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • java easyPOI实现导出一对多数据

    java easyPOI实现导出一对多数据

    这篇文章主要为大家详细介绍了java如何利用easyPOI实现导出一对多数据,并且可以设置边框、字体和字体大小,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • Java中的main方法调用非静态方法处理

    Java中的main方法调用非静态方法处理

    这篇文章主要介绍了Java中的main方法调用非静态方法处理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • 详解JAVA高质量代码之数组与集合

    详解JAVA高质量代码之数组与集合

      在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述Java高质量代码之数组与集合
    2013-08-08
  • Java虚拟机JVM类加载机制(从类文件到虚拟机)

    Java虚拟机JVM类加载机制(从类文件到虚拟机)

    所谓的类加载机制就是虚拟机将class文件加载到内存,并对数据进行验证,转换解析和初始化,形成虚拟机可以直接使用的java类型,本文给大家介绍类加载机制过程从类文件到虚拟机的详细说明,感兴趣的朋友跟随小编一起看看吧
    2021-06-06
  • 详解Springboot快速搭建跨域API接口的步骤(idea社区版2023.1.4+apache-maven-3.9.3-bin)

    详解Springboot快速搭建跨域API接口的步骤(idea社区版2023.1.4+apache-maven-3.9.

    这篇文章主要介绍了Springboot快速搭建跨域API接口(idea社区版2023.1.4+apache-maven-3.9.3-bin),本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Struts2动态结果集代码示例

    Struts2动态结果集代码示例

    这篇文章主要介绍了Struts2动态结果集的有关内容,涉及具体代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • Java super关键字的使用方法详解

    Java super关键字的使用方法详解

    这篇文章主要介绍了Java super关键字的使用方法详解的相关资料,希望通过本文能帮助到大家,让大家对super关键字彻底掌握,需要的朋友可以参考下
    2017-10-10
  • Java中数组的定义与使用详解

    Java中数组的定义与使用详解

    这篇文章主要给大家介绍了关于Java中数组的定义与使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-11-11
  • 使用Java编写导出不确定行数列数数据的工具类

    使用Java编写导出不确定行数列数数据的工具类

    这篇文章主要为大家详细介绍了如何使用Java编写导出不确定行数列数数据的工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03

最新评论