Java策略模式,与根据SpringBoot的监听在项目中实现应用

Java策略模式,与根据SpringBoot的监听在项目中实现应用

这段时间在公司接了一个新的需求,用策略模式来重构我们的支付模块,在该模块中有多个需要对接的支付接口,而支付接口需要的参数都是差不多的,之前的写的时候为了图方便,都是用的大量的判断调用具体哪个支付接口,渐渐的就造成了代码过于难看,维护困难,需要进行重构

策略模式是什么?

策略模式主要就是用来解决大量的判断场景下,用接口和其实现类来进行简化模块,达到去除if的目的,使代码更容易维护,不过前提是需要确定接口需要实现的方法有哪些,实现的方法中的参数是什么,不然如果接口没有设计好的话,之后的一点改动都会影响所有实现该接口的类,在使用该模式时,必须要想好这两个问题。

策略模式的应用场景

用于大量判断来执行一些操作很类似的,可以根据某些特征来区分的行为
就比如上面说的,支付模块,支付模块里主要就是几个主要方法,下单,订单查询,退款,退款查询,支付回调接口。而且这几个接口的参数大致相同,因此可以用策略模式完美解决大量if的问题。

使用策略模式和不使用策略模式的代码区别

这是没有使用策略模式的支付下单接口:

//判断支付方式
        switch (type){
            //支付 1
            case 0:
                return pay1.order();
            //支付2
            case 1:
                return pay2.order();
            case 2:
            	return pay3.order();
           	case 3:
           		return pay4.order();
                default:
                    return "请检查是否配置了支付方式";
        }

如果再对接一个支付,那下单,退款等方法是不是又要增加一个case?这还是没有增加任何操作的下单,如果加入了其他操作的话那代码可读性那肯定更差了。维护起来也会越来越麻烦。

这是使用策略模式的支付下单接口:

IPayImpl payObj=payServiceContext.get(type);
        if(payObj==null){
            return "未配置支付方式。";
        }
        return payObj.order();

这对比起来是不是看起来就简洁多了呢?再对接接口只要添加一个实现类就好了,调用类根本不需要再做其他的改变。

下面是策略模式的实现

首先先创建一个接口,所有对接的支付方法都要实现该接口

package com.lin.pay.service.impl;

/**
 * 支付接口的接口类
 * @Author: lin
 */
public interface IPayImpl {

    /**
     * 下单
     * @return 返回下单结果
     * @throws Exception 类型装换或解密时的异常
     */
    String wxPreCreate()throws Exception;

    /**
     * 订单查询
     * @return 查询返回结果
     * @throws Exception 类型装换或解密时的异常
     */
    String commonQuery() throws Exception;

    /**
     * 退款
     * @return 退款返回结果
     * @throws Exception 类型装换或解密时的异常
     */
    String commonRefund() throws Exception;

    /**
     * 退款查询
     * @return 退款查询返回结果
     * @throws Exception 类型装换或解密时的异常
     */
    String refundQuery() throws Exception;

    /**
     * 异步通知
     * @return
     * @throws Exception
     */
    String notify() throws Exception;
}

接下来创建一个实现类

/**
 * @Author: lin
 */
@Service
@Slf4j
//实现类必须使用的自定义注解,来判断支付类型
@PayTypeAnnotation(PayTypeEnum.PAY0)
public class FyIPayService implements IPayImpl {

	@Override
    String wxPreCreate()throws Exception{
    	return "";
    }

    @Override
    String commonQuery() throws Exception{
    	return "";
    }

    @Override
    String commonRefund() throws Exception{
    	return "";
    }

    @Override
    String refundQuery() throws Exception{
    	return "";
    }

    @Override
    String notify() throws Exception{
    	return "";
    }
}

该类实现支付接口后,所有的逻辑都在实现类里写,再使用注解来标识他的支付类型,在下面的springboot监听里会写到。

创建一个自定义注解,来区分支付类型

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 支付接口注解,如果新增了支付接口就必须要更新该注解,并引用到支付接口的实现类
 * @Author: lin
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayTypeAnnotation {
    PayTypeEnum value();
}

注解里使用的枚举类:

/**
 * @Author: lin
 */
public enum PayTypeEnum {
    /**
     * 支付类型
     */
    PAY0(0,"支付1"),
    PAY1(1,"支付2");
    private Integer type;
    private String name;

    PayTypeEnum(Integer type,String name){
        this.type=type;
        this.name=name;
    }

    public Integer getType(){
        return type;
    }

    public String getName() {
        return name;
    }
}

不用注解也行,可以在接口类里增加一个type字段,让实现类强制实现这个字段,根据字段进行区分,不过这个方法虽然简单点,但是不推荐使用,使用注解的话代码易读性会更好。

使用springboot的监听机制来进行存贮各种支付类型

首先创建一个map,来存贮接口的实现类

/**
 * 支付服务map
 * 类中维护了一个Map,用来存放IPayImpl的实现类,然后通过@Component交由Spring容器管理
 * @Author: lin
 */
@Component
public class PayServiceContext {

    /**
     * 用来存储支付类型如:聚合,富友支付的实现类
     */
    private final static Map<Integer, IPayImpl> PAY_MAP;


    static {
        PAY_MAP=new HashMap<>();
    }

    public IPayImpl get(Integer type){
        return PAY_MAP.get(type);
    }

    public void put(Integer type, IPayImpl payObj){
        PAY_MAP.put(type,payObj);
    }

接下来创建一个springboot的监听,在启动时将实现类新增进去

/** 定义Springboot的监听器
 * 项目启动后用来处理自定义支付接口,先拿到每个添加了自定义注解的类,然后通过反射拿到该类的自定义注解,
 * 再通过自定义注解中的值(支付类型枚举),然后把该值添加进中Map中
 * @Author: lin
 */
@Component
@Slf4j
public class PayTypeListener implements ApplicationListener<ContextRefreshedEvent> {

    @Resource
    private PayServiceContext payServiceContext;

    @Override
    public void onApplicationEvent(@NotNull ContextRefreshedEvent event) {
        Map<String, IPayImpl> beans = event.getApplicationContext().getBeansOfType(
                IPayImpl.class);
        log.info("正在获取支付接口实现类");
        beans.forEach((k, calcService) -> {
            Class clazz = calcService.getClass();
            PayTypeAnnotation payTypeListener = (PayTypeAnnotation)clazz.getAnnotation(PayTypeAnnotation.class);
            payServiceContext.put(payTypeListener.value().getType(), calcService);
        });
        log.info("支付接口实现类获取完成");
    }

大功告成!接下来只需要简单的调用就好了,调用方式为:

@Service
@Slf4j
public class test{
	@Autowired
    private PayServiceContext payServiceContext;
	
	public String test(Integer type){
		IPayImpl payObj=payServiceContext.get(payType);
        if(payObj==null){
            return "未配置支付方式。";
        }
        return payObj.wxPreCreate();
	}
}

最后总结,使用设计模式来优化代码是非常棒的,如果一个项目使用了很多的设计模式,那维护起来也非常轻松,就不会出现那种,不敢碰的祖传代码了哈哈哈哈哈

本文参考资料:https://blog.csdn.net/lovexiaotaozi/article/details/103910776#comments

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值