美文网首页
策略+工厂+注解实战

策略+工厂+注解实战

作者: 8813d76fee36 | 来源:发表于2018-05-29 18:09 被阅读53次

场景

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

简单实现

  • 现在假设PayService类实现如下:
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");
    }
}
  • 测试结果
    测试结果
    这种方式能够满足我们的需求,但是一旦支付模式有增加(比如引入银联、微信H5、微信公众号等)或者减少,那么就需要不停地维护userPay(String channel)方法。针对这个问题,我们可以使用策略模式将选择渠道处理方式的过程与负责具体支付逻辑的userPay(String channel)方法解耦。

引入策略模式

策略模式

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

  • Context持有一个策略的引用,这样它将无需关心策略的具体实现(本例中对应的就是PayService类)。
  • Strategy接口是同类策略的一个抽象,同一类策略都将实现这个接口,并完成策略的具体逻辑。
  • ConcreteStrateyA等是策略的具体实现。

策略接口

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

public interface PayMode {
    void pay();
}

策略实现

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

  • WxPayMode
public class WxPayMode implements PayMode {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}
  • AlipayMode
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语句显示地做判断,为了解决这个问题,可以使用工厂+注解。

策略+工厂+注解

项目结构


项目结构
  • 新建@Channel注解,表示支付渠道
@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("支付宝支付");
    }
}
  • PayService改造
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");
    }
}

相关文章

  • 策略+工厂+注解实战

    场景 在对接支付接口时,不同的支付渠道需要做不同的处理。后台接口可以要求前端将用户选择的支付渠道以参数的形式传递过...

  • Android & Java 注解和自定义注解处理器

    写在前面:本文是实际工作中学习成果,记为笔记 目录 背景 什么是注解 注解实战:动态注解 注解实战:静态注解 注解...

  • Java Excel (Apache POI + annotat

    思路: 自定义注解, 导出/读取 excel 根据注解自动解析字段 注解 注解与excel mapping 工厂,...

  • 策略、工厂模式融合 InitializingBean

    策略、工厂模式融合 InitializingBean 策略、工厂模式分别是什么 策略模式 策略模式是将不同的算法封...

  • Spring 常用注解解析

    原生注解 @Retention: 定义注解的保留策略 @Target: 定义注解的作用目标 @Document: ...

  • 自定义注解

    注解分类 1、代码注解2、编译时注解3、运行时注解 注解范例 使用注解的类 注解解析类 注解实战 需求1、有一张用...

  • 设计模式之策略模式

    设计模式(策略模式实战) 一.分类 java的设计模式大体上分为三大类: 创建型模式(5种): 工厂方法模式,抽象...

  • 设计模式六策略工厂注解实例应用

    前景回顾: 假设我们有一个超市会员的场景,根据不同的消费额制定不同的策略,用上文的方法设计好策略后,在用户结账的时...

  • Spring注解配置工作原理源码解析

    【Spring实战】Spring注解配置工作原理源码解析

  • 2019-03-29

    <<机器学习实战>>--策略梯度

网友评论

      本文标题:策略+工厂+注解实战

      本文链接:https://www.haomeiwen.com/subject/mxuajftx.html