模板方法设计模式

介绍:

在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑 (算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用 算法)是相同的。Template 提供了这种情况的一个实现框架。 Template 模式是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并 定义好细节的接口,子类中实现细节。【注释 1

【注释 1Strategy 模式解决的是和 Template 模式类似的问题,但是 Strategy 模式是将逻辑 (算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。

结构图:

模板方法设计模式

模板方法的优缺点:

优点:

模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。

缺点:

每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。

使用场景:

在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。

代码:

代码结构:

模板方法设计模式

maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
<dependencies>
    <!-- sprinboot web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>
</dependencies>

TemplateController

package com.ldq.controller;

import com.ldq.AbstractPayCallbackTemplate;
import com.ldq.factory.TemplateFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 16:10
 * @Description:
 */
@RestController
public class TemplateController {
    @RequestMapping("/asyncCallBack")
        public String asyncCallBack(String templateId){
        AbstractPayCallbackTemplate payCallbackTemplate = TemplateFactory.getPayCallbackTemplate(templateId);
        return  payCallbackTemplate.asyncCallBack();

    }
}

TemplateFactory

package com.ldq.factory;

import com.ldq.AbstractPayCallbackTemplate;
import com.ldq.utils.SpringUtils;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 16:07
 * @Description:
 */
public class TemplateFactory {
    /**
     * 使用工厂模式获取模板
     * @param templateId
     * @return
     */
    public static AbstractPayCallbackTemplate getPayCallbackTemplate(String templateId){
        AbstractPayCallbackTemplate abstractPayCallbackTemplate = SpringUtils.getBean(templateId, AbstractPayCallbackTemplate.class);
        return abstractPayCallbackTemplate;
    }
}

AliPayCallbackTemplate

package com.ldq.impl;

import com.ldq.AbstractPayCallbackTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 16:02
 * @Description:
 */
@Slf4j
@Component
public class AliPayCallbackTemplate extends AbstractPayCallbackTemplate {
    @Override
    protected String asyncService(Map<String, String> verifySignature) {
        log.info(">>>>>第三步 支付宝支付 asyncService()verifySignatureMap:{}", verifySignature);
        String paymentStatus = verifySignature.get("aliPayMentStatus");
        if (paymentStatus.equals("1")) {
            String aliPayOrderNumber = verifySignature.get("aliPayOrderNumber");
            log.info(">>>>orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付...");
        }

        return resultSuccess();
    }

    private String resultSuccess() {
        return "success";
    }

    @Override
    protected String resultFail() {
        return "fail";
    }

    @Override
    protected Map<String, String> verifySignature() {
        //>>>>假设一下为阿里pay回调报文>>>>>>>>>>>>>>>>
        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");
        //>>>>假设一下为阿里pay回调报文结束>>>>>>>>>>>>>>>>

        // 解析报文是否成功 或者验证签名成功返回 200 为成功..
        verifySignature.put("analysisCode", "200");
        return verifySignature;
    }
}

UnionPayCallbackTemplate

package com.ldq.impl;

import com.ldq.AbstractPayCallbackTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 16:04
 * @Description:
 */
@Slf4j
@Component
public class UnionPayCallbackTemplate extends AbstractPayCallbackTemplate {
    @Override
    protected String asyncService(Map<String, String> verifySignature) {
        log.info(">>>>>第三步 银联回调  asyncService()verifySignatureMap:{}", verifySignature);
        String paymentStatus = verifySignature.get("unionPayMentStatus");
        if (paymentStatus.equals("1")) {
            String aliPayOrderNumber = verifySignature.get("aliPayOrderNumber");
            log.info(">>>>orderNumber:{aliPayOrderNumber},已经支付成功 修改订单状态为已经支付...");
        }

        return resultSuccess();
    }

    @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("unionPayMentStatus", "1");
        verifySignature.put("unionPayOrderNumber", "201910101011");
        //>>>>假设一下为阿里pay回调报文结束>>>>>>>>>>>>>>>>

        // 解析报文是否成功 或者验证签名成功返回 200 为成功..
        verifySignature.put("analysisCode", "200");
        return verifySignature;
    }

    private String resultSuccess() {
        return "ok";
    }

    @Override
    protected String resultFail() {
        return "fail";
    }
}

SpringUtils

package com.ldq.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

AbstractPayCallbackTemplate

package com.ldq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 15:53
 * @Description:
 */
@Slf4j
public abstract class AbstractPayCallbackTemplate {
    /**
     * 定义相同的骨架
     * @return
     */
    public String asyncCallBack(){

        // 1.验证参数和验证签名
        Map<String, String> verifySignature = verifySignature();
        // 2.日志收集 相同
        payLog(verifySignature);
        // 3. 获取验证签名状态
        String analysisCode = verifySignature.get("analysisCode");
        if(!"200".equals(analysisCode)){
            return resultFail();
        }
        // 4.更改数据库状态同时返回不同支付结果
        return asyncService(verifySignature);
    }

    /**
     * 提交到数据库获取返回结果
     * @param verifySignature
     * @return
     */
    protected abstract String asyncService(Map<String,String> verifySignature);

    /**
     * 返回失败结果
     * @return
     */
    protected abstract String resultFail();

    /**
     * 执行修改状态和返回不同的结果
     * @param verifySignature
     */
    @Async
    protected  void payLog(Map<String,String> verifySignature){
        log.info("写入数据库....verifySignature:{}",verifySignature);
    }

    protected abstract Map<String,String> verifySignature();
}
AppTemplate
package com.ldq;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;

/**
 * @Auther: liangdeqiang
 * @Date: 2019-5-12 16:12
 * @Description:
 */
@SpringBootApplication
@EnableAsync
public class AppTemplate {
    public static void main(String[] args) {
        SpringApplication.run(AppTemplate.class);
    }
}

源于:http://www.mayikt.com/