自定义注解(三)支付渠道:消除if-策略模式+工厂模式+单例模式

自定义支付注解=消除if:策略模式+工厂模式+单例模式

代码取景,知识来源于视频《云析学院【路飞老师】-一次学习终身受用-如何正确使用设计模式写出优雅的代码》

1、定义注解标签 PayChannel

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PayChannel {
    int channelId();
}

2、创建支付渠道策略接口及其不同实现类

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");
    }
}

有需要的话继续扩展,创建实现类即可

3、创建工厂类

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();
    }
}

4、测试功能

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

你可能感兴趣的:(Spring)