需求:
- 完成支付模块需要支持微信支付,支付宝支付,通过传入code区分不同的支付方式,完成不同的支付逻辑
- 我们首先想到的是用if 判断支付方式 :
if(payType.getCode == 101){
// 支付宝支付
} else if(payType.getCode == 102){
// 微信支付逻辑
}
但是如果我们需要增加一个银联支付,则需要继续改动业务逻辑,添加更多的if else,这样明显不符合设计原则中的开闭原则:对扩展开放,对修改关闭
所以产生了如下的解决方式:
- PayCode.java 支付方式自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PayCode {
int value();
String name();
}
- Pay.java 支付接口
public interface Pay {
/**
* pay
*/
void pay();
}
- AliPay.java 支付宝支付业务逻辑
@PayCode(value = 101, name = "支付宝")
public class AliPay implements Pay{
@Override
public void pay() {
System.out.println("执行支付宝支付逻辑...");
}
}
- WechatPay.java 微信支付业务逻辑
@PayCode(value = 102, name = "微信")
public class WechatPay implements Pay{
@Override
public void pay() {
System.out.println("执行微信支付逻辑...");
}
}
- PayEnum 支付方式枚举类
@Getter
public enum PayEnum {
ALI_PAY(101,"支付宝支付"),
WECHAT_PAY(102, "微信支付");
private Integer code;
private String msg;
PayEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
- PayConfiguration.java 让Spring扫描到注解标记的类
@Configuration
@ComponentScan(includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = PayCode.class)
})
public class PayConfiguration {
}
- TestService.java 监听器,从spring容器得到被PayCode注解标记类的对象,并通过传入的code调用调用不同的pay方法
@Service
public class TestService implements ApplicationListener<ContextRefreshedEvent> {
private Map<Integer, Pay> payMap = null;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);
payMap = new ConcurrentHashMap<>();
beansWithAnnotation.forEach((key, value) -> {
Integer type = value.getClass().getAnnotation(PayCode.class).value();
payMap.put(type, (Pay) value);
});
}
public void pay(PayEnum payEnum) {
payMap.get(payEnum.getCode()).pay();
}
}
- DemoTest.java 测试类
public class DemoTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(PayConfiguration.class);
TestService testService = context.getBean("testService", TestService.class);
testService.pay(PayEnum.ALI_PAY);
testService.pay(PayEnum.WECHAT_PAY);
}
}
- 结果
执行支付宝支付逻辑...
执行微信支付逻辑...
- 这样,我们即便在将来的业务中需要添加银联支付,也不需要改动原有代码,新增一个银联支付的类即可