java策略模式解决支付问题,消除if、else,代码可运行

本来打算1024发搞个徽章,结果记错时间了(。•́︿•̀。)

策略模式解决支付问题

  • 1.业务场景
  • 2.解决方案
  • 3.代码设计
    • 3.1首先建立如下的包目录结构
    • 3.2在enums包下新建支付方式的注解,代码如下
    • 3.3 annotation包下新建支付方式的注解,代码如下
    • 3.4 service包下新建支付服务接口,代码如下
    • 3.5 strategy包下新建支付服务的策略实现类
      • 3.5.1 支付宝支付策略类:
      • 3.5.2微信支付策略类
    • 3.6 pay包下新建支付服务策略工厂
    • 3.7代码中调用

1.业务场景

支付方式有支付宝支付、微信支付、网银支付等等,如果在代码中通过不断的写if-elseif去实现的话,虽然看起来更直观,但实际上不利于后续的扩展和维护,后期如果由于业务需要使用混合支付的话,就需要改动if-elseif的逻辑,违反了开闭原则,代码如下:

String payTypeCode = "WX";
if ("WX".equals(payTypeCode)){
    System.out.println("微信支付");
}else if ("ALI".equals(payTypeCode)){
    System.out.println("支付宝支付");
}else if ("WANGYIN".equals(payTypeCode)){
    System.out.println("网银支付");
}else {
    System.out.println("混合支付支付");
}

2.解决方案

通过工厂模式+策略模式+自定义注解的方式彻底消除if-elseif,提高代码的可扩展性,最终达到实现开闭原则的目的

3.代码设计

3.1首先建立如下的包目录结构

pay
    annotation          //支付方式自定义注解
    enums               //支付方式枚举类
    service             //支付服务接口
        strategy        //支付服务接口的策略实现类

3.2在enums包下新建支付方式的注解,代码如下

@Getter
public enum PayTypeEnum {
    /**
     * 微信支付
     */
    WX("WX","微信支付"),

    /**
     * 支付宝支付
     */
    ALI("ALI","支付宝");

    /**
     * 支付方式内部编码
     */
    private String code;

    /**
     * 支付方式名称
     */
    private String info;

    /**
     * 构造方法
     * @param code 支付方式内部编码
     * @param info 支付方式名称
     */
    PayTypeEnum(String code, String info) {
        this.code = code;
        this.info = info;
    }

    /**
     * 根据code获取枚举
     * @param code 支付方式内部编码
     * @return 支付方式
     */
    public static PayTypeEnum getValue(String code) {
        for (PayTypeEnum payType : values()) {
            if (payType.code.equals(code)) {
                return payType;
            }
        }
        return null;
    }
}

3.3 annotation包下新建支付方式的注解,代码如下

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PayType {

    /**
     * 支付方式的值为PayTypeEnum枚举
     * @return
     */
    PayTypeEnum value();
}

3.4 service包下新建支付服务接口,代码如下

public interface PayService {

    /**
     * 支付
     */
    void pay();
}

3.5 strategy包下新建支付服务的策略实现类

3.5.1 支付宝支付策略类:

@PayType(value = PayTypeEnum.ALI)
@Service
public class AliPayServiceStrategy implements PayService {
    /**
     * 支付
     */
    @Override
    public void pay() {
        System.out.println("支付宝支付成功");
    }
}

3.5.2微信支付策略类

@PayType(value = PayTypeEnum.WX)
@Service
public class WxPayServiceStrategy implements PayService {
    /**
     * 支付
     */
    @Override
    public void pay() {
        System.out.println("微信支付成功");
    }
}

3.6 pay包下新建支付服务策略工厂

@Component
public class PayServiceFactory implements ApplicationContextAware {

    /**
     * 支付方式枚举-支付服务的映射集合
     */
    private static final Map<PayTypeEnum, PayService> payServiceMapping = new HashMap<>();

    /**
     * 工厂方法获取支付服务实现
     *
     * @param payTypeCode 支付方式的内部编码
     * @return 支付服务
     */
    public static final PayService getPayService(String payTypeCode) {
        PayTypeEnum payTypeEnum = PayTypeEnum.getValue(payTypeCode);
        if (payTypeEnum == null) {
            throw BusinessException.build("无效的支付编码");
        }
        PayService payService = payServiceMapping.get(payTypeEnum);
        if (payService == null) {
            throw BusinessException.build("没有匹配的支付服务实现类");
        }
        return payService;
    }

    /**
     * 初始化支付枚举-支付服务的映射
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> payServiceMap = applicationContext.getBeansWithAnnotation(PayType.class);
        if (CollectionUtils.isEmpty(payServiceMap)) {
            throw BusinessException.build("支付服务映射初始化失败");
        }
        payServiceMap.forEach((key,bean) -> {
            if (!(bean instanceof PayService)) {
                throw BusinessException.build("注解:" + PayType.class + ",只能用于" + PayService.class + "的实现类中");
            }
            PayService payService = (PayService)bean;
            PayType annotation = payService.getClass().getAnnotation(PayType.class);
            payServiceMapping.put(annotation.value(),payService);
        });
    }

}

3.7代码中调用

 /**
     * 根据前端选择的支付方式进行支付
     *
     * @param payTypeCode 支付方式内部编码code
     */
    @GetMapping("/pay")
    public void pay(String payTypeCode) {

        //根据支付编码获取支付服务
        PayService payService = PayServiceFactory.getPayService(payTypeCode);

        //实际的支付业务操作
        payService.pay();

    }

通过传入的支付方式编码,输出不同的内容 微信支付成功 或者 支付宝支付成功

你可能感兴趣的:(java,策略模式,java,开发语言,设计模式)