需求:
- 完成支付模块需要支持微信支付,支付宝支付,通过传入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();
}
对注解类上的注解有疑问的,点这个:
https://blog.csdn.net/qq_45752401/article/details/111653365
- 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("执行微信支付逻辑...");
}
}
- PayConfiguration.java 让Spring扫描到注解标记的类
@Configuration // 被@configuration修饰,为配置类
@ComponentScan(includeFilters = { // 扫描本身及延伸类
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = PayCode.class) // 扫描被@PayCode注解修饰的类
})
public class PayConfiguration {
}
- MyqxinService.java 监听器,从spring容器得到被PayCode注解标记类的对象,并通过传入的code调用调用不同的pay方法
@Service
public class MyqxinService implements ApplicationListener<ContextRefreshedEvent> { // 监听spring容器
private Map<Integer,Pay> payMap = null; // if else
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 获取上下文对象
ApplicationContext applicationContext = event.getApplicationContext();
// 获取被PayCode注解修饰的实例对象 Map<String,Object> String: 默认key ;Object 实例对象
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(PayCode.class);
// ConcurrentHashMap线程安全的HashMap 使用场景,Map的成员变量推荐使用。而如方法内的局部变量则推荐使用 HashMap
payMap = new ConcurrentHashMap<>();
beans.forEach((key,value) -> {
// key spring默认命令方式的名称 ;value 实例对象
// getAnnotation获取该类上的@PayCode注解,并获注解上的value值
Integer type = value.getClass().getAnnotation(PayCode.class).value();
// 保存map
payMap.put(type,(Pay) value);
});
}
/**
* 实例调用
* @param code
*/
public void pay(Integer code){
payMap.get(code).pay();
}
}
- DemoTest.java 测试类
public class DemoTest {
public static void main(String[] args) {
// 初始化spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PayConfiguration.class);
// 获取实例对象
MyqxinService myqxinService = applicationContext.getBean("myqxinService", MyqxinService.class);
// 调用
myqxinService.pay(101);
myqxinService.pay(102);
}
}
-
结果
注意:
红框这里是spring初始化后,容器里面的实例对象名称,我们在获取实例对象的时候,如果名称写错了就会抛出异常
- DemoTest.java 测试类
public class DemoTest {
public static void main(String[] args) {
// 初始化spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PayConfiguration.class);
// 获取实例对象
MyqxinService myqxinService = applicationContext.getBean("myqxinservice", MyqxinService.class);
// 调用
myqxinService.pay(101);
myqxinService.pay(102);
}
}
异常如下:
- 这样,我们即便在将来的业务中需要添加银联支付,也不需要改动原有代码,新增一个银联支付的类即可
- UnionPay.java 银联支付业务逻辑
@PayCode(value = 103,name = "银联")
public class UnionPay implements Pay {
@Override
public void pay() {
System.out.println("执行银联支付逻辑。。。");
}
}
- DemoTest.java 测试类
public class DemoTest {
public static void main(String[] args) {
// 初始化spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PayConfiguration.class);
// 获取实例对象
MyqxinService myqxinService = applicationContext.getBean("myqxinService", MyqxinService.class);
// 调用
myqxinService.pay(101);
myqxinService.pay(102);
myqxinService.pay(103);
}
}
-
结果