【日常业务开发】策略+工厂模式优化 if...else判断逻辑
- 场景
- 策略+工厂模式优化
- 利用Spring自动注入的特点处理
- 继承InitializingBean+静态工厂方法调用处理
- 注解+CommandLineRunner+ApplicationContextAware处理/ApplicationListener\<ContextRefreshedEvent>
场景
业务中经常有支付业务,项目刚开始所有业务使用支付宝支付,后面湖南地区需要使用微信支付,然后湖北又需要使用易宝支付,后期可能还有扩展。如果使用if…else逻辑,业务中经常要写的代码:
public static void pay() {
// String fruit = "aliPay";
// String fruit = "yiBaoPay";
String payType = "weiXinPay";
if ("aliPay".equals(payType)){
log.info("===调用支付宝接口发起支付业务===");
} else if ("yiBaoPay".equals(payType)){
log.info("===调用易宝接口发起支付业务===");
} else {
log.info("===调用微信接口发起支付业务===");
}
}
如何优雅的处理消除if…else逻辑,方面后期扩展呢?策略+工厂模式优化
策略+工厂模式优化
利用Spring自动注入的特点处理
支付接口IPay和具体实现类AliPay、WeiXinPay、YiBaoPay
public interface IPay {
String pay();
}
@Service
@Slf4j
public class AliPay implements IPay {
@Override
public String pay() {
log.info("===调用支付宝接口发起支付业务===");
return "调用支付宝接口发起支付业务";
}
}
@Service
@Slf4j
public class WeiXinPay implements IPay {
@Override
public String pay() {
log.info("===调用微信接口发起支付业务===");
return "调用微信接口发起支付业务";
}
}
@Service
@Slf4j
public class YiBaoPay implements IPay {
@Override
public String pay() {
log.info("===调用易宝接口发起支付业务===");
return "调用易宝接口发起支付业务";
}
}
工厂类PayFactory
@Component
public class PayFactory {
/**
* 利用Spring自动注入的特点。Key为bean的名称、value为IPay接口对应的bean实现类
*/
@Autowired
Map<String, IPay> map;
public IPay getInstance(String type) {
return map.get(type);
}
}
@RestController
public class PayController {
@Autowired
private PayFactory payFactory;
@GetMapping("/alipay")
public String aliPay(String type) {
IPay pay = payFactory.getInstance(type);
return pay.pay();
}
}
Key为bean的名称、value为IPay接口对应的bean实现类。对应的业务类型不好扩展
继承InitializingBean+静态工厂方法调用处理
public interface IPay extends InitializingBean {
String pay();
}
@Service
@Slf4j
public class AliPay implements IPay {
@Override
public String pay() {
log.info("===调用支付宝接口发起支付业务===");
return "调用支付宝接口发起支付业务";
}
@Override
public void afterPropertiesSet() throws Exception {
PayFactory.registerHandler("ali", this);
}
}
@Service
@Slf4j
public class WeiXinPay implements IPay {
@Override
public String pay() {
log.info("===调用微信接口发起支付业务===");
return "调用微信接口发起支付业务";
}
@Override
public void afterPropertiesSet() throws Exception {
PayFactory.registerHandler("weixin", this);
}
}
@Service
@Slf4j
public class YiBaoPay implements IPay {
@Override
public String pay() {
log.info("===调用易宝接口发起支付业务===");
return "调用易宝接口发起支付业务";
}
@Override
public void afterPropertiesSet() throws Exception {
PayFactory.registerHandler("yibao", this);
}
}
工厂类PayFactory,暴露注册bean到工厂容器Map对象方法,提供根据type类型查询bean的静态方法
public class PayFactory {
private static final Map<String, IPay> PAY_MAP = new HashMap<>();
/**
* 获取对应实例Bean
* @param type
* @return
*/
public static IPay getInstance(String type) {
return PAY_MAP.get(type);
}
/**
* 注册bean到工厂容器对象
* @param handlerName
* @param pay
*/
public static void registerHandler(String handlerName, IPay pay) {
PAY_MAP.put(handlerName, pay);
}
}
注解+CommandLineRunner+ApplicationContextAware处理/ApplicationListener<ContextRefreshedEvent>
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PayCode {
String value();
String name();
}
public interface IPay {
String pay();
}
@PayCode(value = "alia", name = "支付宝支付")
@Service
@Slf4j
public class AliPay implements IPay {
@Override
public String pay() {
log.info("===调用支付宝接口发起支付业务===");
return "调用支付宝接口发起支付业务";
}
}
@PayCode(value = "weixin", name = "微信支付")
@Service
@Slf4j
public class WeiXinPay implements IPay {
@Override
public String pay() {
log.info("===调用微信接口发起支付业务===");
return "调用微信接口发起支付业务";
}
}
@PayCode(value = "yibao", name = "易宝支付")
@Service
@Slf4j
public class YiBaoPay implements IPay {
@Override
public String pay() {
log.info("===调用易宝接口发起支付业务===");
return "调用易宝接口发起支付业务";
}
}
第一种方式: 工厂类PayFactory实现Spring生命周期函数在run方法中处理被标记的@PayCode的bean对象加入到静态容器Map中:
-
CommandLineRunner:当前Bean被IOC容器装配完成调用run()方法
-
ApplicationContextAware: 获取容器对象ApplicationContext
@Component
public class PayFactory implements CommandLineRunner, ApplicationContextAware {
private ApplicationContext applicationContext;
private static final Map<String, IPay> PAY_MAP = new HashMap<>();
/**
* 获取对应实例Bean
* @param type
* @return
*/
public static IPay getInstance(String type) {
return PAY_MAP.get(type);
}
@Override
public void run(String... args) throws Exception {
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);
if (beansWithAnnotation !=null ) {
beansWithAnnotation.forEach((k,v)->{
PayCode payCodeAnn = v.getClass().getAnnotation(PayCode.class);
PAY_MAP.put(payCodeAnn.value(), (IPay)v);
});
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
第二种方式: 实现ApplicationListener<ContextRefreshedEvent>监听事件接口
代替CommandLineRunner, ApplicationContextAware
。
ContextRefreshedEvent事件: ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
@Component
public class PayFactory implements ApplicationListener<ContextRefreshedEvent> {
private static final Map<String, IPay> PAY_MAP = new HashMap<>();
/**
* 获取对应实例Bean
* @param type
* @return
*/
public static IPay getInstance(String type) {
return PAY_MAP.get(type);
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);
if (beansWithAnnotation !=null ) {
beansWithAnnotation.forEach((k,v)->{
PayCode payCodeAnn = v.getClass().getAnnotation(PayCode.class);
PAY_MAP.put(payCodeAnn.value(), (IPay)v);
});
}
}
}
@RestController
public class PayController {
@GetMapping("/alipay")
public String aliPay(String type) {
IPay pay = PayFactory.getInstance(type);
return pay.pay();
}
}