策略模式解决支付问题
- 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();
}
通过传入的支付方式编码,输出不同的内容 微信支付成功 或者 支付宝支付成功