代码取景,知识来源于视频《云析学院【路飞老师】-一次学习终身受用-如何正确使用设计模式写出优雅的代码》
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PayChannel {
int channelId();
}
1)定义价格接口PayStrategy
public interface PayStrategy {
/**
* 根据渠道计算价格
* @param channelId
* @param goodsId
* @return
*/
BigDecimal calRecharge(Integer channelId,Integer goodsId);
}
2)创建不同的价格接口实现类,
包名:com.yf.custom.pay.impl
工商银行
@PayChannel(channelId = 1)
public class ICBCBank implements PayStrategy{
@Override
public BigDecimal calRecharge(Integer channelId, Integer goodsId) {
return new BigDecimal("1");
}
}
招商银行
@PayChannel(channelId = 2)
public class CMBCBank implements PayStrategy{
@Override
public BigDecimal calRecharge(Integer channelId, Integer goodsId) {
return new BigDecimal("2");
}
}
有需要的话继续扩展,创建实现类即可
1)单例模式获取 PayStrategyFactory实例;
2)扫描指定实现类,存储所有的payChannel信息;
ps:Reflections依赖maven如下:
<dependency>
<groupId>org.reflectionsgroupId>
<artifactId>reflectionsartifactId>
<version>0.9.10version>
dependency>
3)根据类名调用对应实现类方法,见create(String channelId)
public class PayStrategyFactory {
//饿汉式 单例模式
private static PayStrategyFactory payStrategyFactory=new PayStrategyFactory();
/**
* 单例模式-私有构造器
*/
private PayStrategyFactory(){
}
public static PayStrategyFactory getInstance(){
return payStrategyFactory;
}
/**
* 重点:存储所有的payChannel
*/
public static HashMap<Integer,String> payChannelMap=new HashMap<>();
static {
//1、扫描支付渠道的实现类 ,Reflections 依赖 Google 的 Guava 库和 Javassist 库
Reflections reflections = new Reflections("com.yf.custom.pay.impl");
//2、获取所有包含PayChannel注解的类
Set<Class<?>> classList = reflections.getTypesAnnotatedWith(PayChannel.class);
for (Class clazz : classList) {
PayChannel t = (PayChannel) clazz.getAnnotation(PayChannel.class);
//3、赋值payChannelMap,存储所有的支付渠道
payChannelMap.put(t.channelId(), clazz.getCanonicalName());
}
}
/**
* 根据channelId获取对应的具体实现
* @param channelId
* @return
*/
public PayStrategy create(Integer channelId) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//1.获取渠道对应的类名
String clazz=payChannelMap.get(channelId);
Class clazz_=Class.forName(clazz);
/**
* newInstance :工厂模式经常使用newInstance来创建对象,newInstance()是实现IOC、反射、依赖倒置 等技术方法的必然选择
* 调用class的加载方法加载某个类,然后实例化
*
* new 只能实现具体类的实例化,不适合于接口编程
*/
return (PayStrategy) clazz_.newInstance();
}
}
http://localhost:8080/calculatePrice?channelId=2&goodsId=123 返回1.00
http://localhost:8080/calculatePrice?channelId=2&goodsId=123 返回2.00
验证成功
完整代码地址:https://gitee.com/yyhcsfy/LearningDemo/tree/master/spring-custom-annotation/src/main/java/com/yf/custom/pay