策略+工厂+注解实战

2018-05-29  本文已影响53人  8813d76fee36

场景

在对接支付接口时,不同的支付渠道需要做不同的处理。后台接口可以要求前端将用户选择的支付渠道以参数的形式传递过来,然后我们就可以通过这个参数来判断究竟该采用处理方式来完成接口对接操作。
假设参数channel代表支付渠道,可选值为wxalipay,分别代表微信APP支付和支付宝支付。
PayService类的userPay(String channel)方法负责具体的对接逻辑。

简单实现

public class PayService {

    public void userPay(String channel) {
        if ("wx".equals(channel)) {
            wxPay();
        }
        if ("alipay".equals(channel)) {
            aliPay();
        }
    }

    private void wxPay() {
        System.out.println("微信支付");
    }

    private void aliPay() {
        System.out.println("支付宝支付");
    }
}
public class Run {
    public static void main(String[] args) {
        PayService payService = new PayService();
        payService.userPay("wx");
    }
}

引入策略模式

策略模式

策略模式分为三个主要角色:

策略接口

新建一个接口PayMode代表支付方式的抽象,其中包含一个抽象方法pay()来代表该方式的具体实现。

public interface PayMode {
    void pay();
}

策略实现

新建WxPayModeAlipayMode类,实现PayMode接口,代表具体的支付实现。

public class WxPayMode implements PayMode {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}
public class AlipayMode implements PayMode {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}

改造PayService

public class PayService {
    
    // 持有策略的引用
    private PayMode payMode;

    public void userPay(String channel) {
        
        if ("wx".equals(channel)) {
            payMode = new WxPayMode();
            payMode.pay();
        }
        if ("alipay".equals(channel)) {
            payMode = new AlipayMode();
            payMode.pay();
        }
    }
}

测试

public class Run {
    public static void main(String[] args) {
        PayService payService = new PayService();
        payService.userPay("alipay");
    }
}
测试结果
此时具体的渠道实现与userPay()方法分离,支付渠道实现逻辑如果有改动则只需要到具体的实现类修改即可,但我们仍需要使用if语句显示地做判断,为了解决这个问题,可以使用工厂+注解。

策略+工厂+注解

项目结构


项目结构
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
public @interface Channel {
    String value();
}
public class PayModeFactory {

    // 获取类加载器
    private final ClassLoader classLoader = getClass().getClassLoader();

    // 策略实现的缓存 Key: channel(渠道) Value: 策略实现类的Class对象
    private final Map<String, Class<?>> payModeMap = new HashMap<>();

    // 策略所在包
    private static final String BASE_PACKAGE = "dev.wj.pay.strategy";

    // 工厂实例
    private volatile static PayModeFactory instance;

    // 私有化构造方法
    private PayModeFactory() {
        init(); //初始化操作,完成注解读取、渠道与策略映射
    }

    // 获取工厂实例
    public static PayModeFactory getInstance() {
        if (instance == null) {
            synchronized (PayModeFactory.class) {
                if (instance == null) {
                    instance = new PayModeFactory();
                }
            }
        }
        return instance;
    }

    private void init() {

        try {
            // 获取BASE_PACKAGE下所有的类文件
            File basePackage
                    = new File(classLoader.getResource(BASE_PACKAGE.replace('.', File.separatorChar)).toURI());

            File[] classFiles = basePackage.listFiles(file -> {
                if (file.getName().endsWith(".class")) {
                    return true;
                }
                return false;
            });

            // 获取PayMode的实现类
            Class<PayMode> payModeClass = PayMode.class;
            for (File classFile : classFiles) {
                Class<?> clazz = classLoader
                        .loadClass(BASE_PACKAGE
                                + "."
                                + classFile.getName().replace(".class", ""));

                if (payModeClass.isAssignableFrom(clazz) && payModeClass != clazz) {
                    // 获得该类上的注解
                    Annotation[] annotations = clazz.getDeclaredAnnotations();
                    // 找到@Channel注解
                    for (Annotation annotation : annotations) {
                        if (annotation instanceof Channel) {
                            // 获得@Channel注解的值
                            String channel = ((Channel) annotation).value();
                            // 将该策略的实现类的Class对象和channel值放入Map缓存起来
                            payModeMap.put(channel, clazz);
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 根据渠道获取策略实现
    public PayMode getPayMode(String channel) {
        try {
            Class<?> clazz = payModeMap.get(channel);
            return (PayMode) clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
@Channel(value = "wx")
public class WxPayMode implements PayMode {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}
@Channel(value = "alipay")
public class AlipayMode implements PayMode {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}
public class PayService {

    // 持有策略的引用
    private PayMode payMode;

    public void userPay(String channel) {
        payMode = PayModeFactory.getInstance().getPayMode(channel);
        payMode.pay();
    }
}
public class Run {
    public static void main(String[] args) {
        PayService payService = new PayService();
        payService.userPay("alipay");
    }
}
上一篇 下一篇

猜你喜欢

热点阅读