demo

  • 该模式涉及三个角色

    • 环境(Context) 角色,持有一个 Strategy 的引用
    • 抽象策略(Strategy)角色: 一个抽象角色,通常由一个接口或抽象类实现。给出所有的具体策略类所需要的接口。
    • 具体策略类(ConcreteStrategy)角色: 包装相关的算法或者行为。

      例子

  • 策略模式 + 单例模式 + 反射 减少 if+else

    抽象策略角色

    ```java package com.nekosighed.api.strategy;

/**

  • 抽象策略角色
  • 定义具体策略类需要实现的方法 / public interface PayStrategy { /*
    • 假设会返回一个支付页面 *
    • @return {@link String } 支付页面 */ public String toPayHtml(); } ```

具体策略角色

  1. 支付宝支付策略类

    1. /**
    2. * 具体策略角色
    3. * alipay
    4. */
    5. public enum AlipayStrategyImpl implements PayStrategy {
    6. SINGLETON;
    7. @Override
    8. public String toPayHtml() {
    9. return "假设是支付宝页面";
    10. }
    11. public static PayStrategy getSingleton() {
    12. System.out.println("获取单例");
    13. return SINGLETON;
    14. }
    15. }
  2. 微信支付策略类 ```java /**

    • 具体策略角色
    • weixin pay */ public enum WexinPayStrategyImpl implements PayStrategy { SINGLETON ; @Override public String toPayHtml() { return “假设是微信支付页面”; }

      public static PayStrategy getSingleton() { System.out.println(“获取单例”); return SINGLETON; } }

  1. <a name="xCNFS"></a>
  2. #### 一个常量
  3. - 定义支付渠道 id 和具体实现策略类 class 的映射
  4. - 也可以改为 支付渠道 id 和具体实现策略类类名的映射
  5. - 也可以将类名存储在 db 中
  6. ```java
  7. /**
  8. * 支付策略枚举
  9. * 对应 支付渠道id-具体的支付实现策略类 class
  10. */
  11. public enum PayStrategyClassName {
  12. ALIPAY_STRATEGY(1, AlipayStrategyImpl.class),
  13. WEXINIPAY_STRATEGY(2, WexinPayStrategyImpl.class),
  14. ;
  15. /**
  16. * 渠道 id
  17. */
  18. private int channelId;
  19. /**
  20. * 具体的支付实现策略类的 class
  21. */
  22. private Class<? extends PayStrategy> className;
  23. /**
  24. * 根据 channelId 获取对应的策略实现类名
  25. *
  26. * @param channelId 支付渠道 id
  27. * @return
  28. */
  29. public static Class<? extends PayStrategy> getPayStrategy(int channelId) {
  30. for (PayStrategyClassName payStrategyClassName: values()) {
  31. if (payStrategyClassName.channelId == channelId) {
  32. return payStrategyClassName.className;
  33. }
  34. }
  35. return null;
  36. }
  37. PayStrategyClassName(int channelId, Class<? extends PayStrategy> className) {
  38. this.channelId = channelId;
  39. this.className = className;
  40. }
  41. public int getChannelId() {
  42. return channelId;
  43. }
  44. public Class<? extends PayStrategy> getClassName() {
  45. return className;
  46. }
  47. }

环境角色

  • 会对获得的具体策略实现类对象进行缓存

    • 减少并发问题,此处缓存了具体策略实现的单例对象
    • 也可以在 map 的 get and set 进行锁

      1. /**
      2. * 1. 环境角色
      3. */
      4. public final class PayStrategyFactory {
      5. private PayStrategyFactory() {
      6. }
      7. /**
      8. * 获取单例的方法名
      9. */
      10. private static String targetMethodName = "getSingleton";
      11. /**
      12. * 缓存
      13. */
      14. private static Map<String, PayStrategy> payStrategyMap = new ConcurrentHashMap<>(2);
      15. /**
      16. * 根据类名 获得 具体策略实现类
      17. *
      18. * @param className 具体策略实现类的类名
      19. * @return {@link PayStrategy}
      20. */
      21. public static PayStrategy getPayStrategy(String className) {
      22. if (Objects.isNull(className) || "".equals(className)) {
      23. return null;
      24. }
      25. if (Objects.isNull(payStrategyMap.get(className))) {
      26. try {
      27. // 反射获得具体策略实现类 class
      28. Class<?> clz = Class.forName(className);
      29. Method method = clz.getDeclaredMethod(targetMethodName);
      30. // 调用获取单例的静态方法
      31. PayStrategy payStrategySingletonInstance = (PayStrategy) method.invoke(null);
      32. // 进行缓存
      33. payStrategyMap.put(className, payStrategySingletonInstance);
      34. System.out.println("缓存支付策略单例ing");
      35. return payStrategySingletonInstance;
      36. } catch (Exception e) {
      37. // TODO start logger
      38. e.printStackTrace();
      39. return null;
      40. }
      41. } else {
      42. System.out.println("从缓存中获取了支付策略单例");
      43. return payStrategyMap.get(className);
      44. }
      45. }
      46. }

调用和输出

  • 调用 ```java public class PayService { public static void startPay(int channelId) {

    1. // 1. 通过渠道 id 获得 类名称
    2. Class<?> cLassName = PayStrategyClassName.getPayStrategy(channelId);
    3. if (Objects.isNull(cLassName)) {
    4. System.out.println("没有对应的支付渠道");
    5. return;
    6. }
    7. // 策略 + 单例 获得具体策略实现类
    8. PayStrategy payStrategy = PayStrategyFactory.getPayStrategy(cLassName.getName());
    9. if (Objects.nonNull(payStrategy)){
    10. System.out.println(payStrategy.toPayHtml());
    11. } else {
    12. System.out.println("没有对应的支付策略");
    13. }

    } }

class Main { public static void main(String[] args) { PayService.startPay(0); System.out.println(“==============”); PayService.startPay(1); System.out.println(“==============”); PayService.startPay(1); System.out.println(“==============”); PayService.startPay(1); System.out.println(“——————-“); PayService.startPay(2); System.out.println(“——————-“); PayService.startPay(2); } }

  1. - 输出
  2. ```shell
  3. 没有对应的支付渠道
  4. ==============
  5. 获取单例
  6. 缓存支付策略单例ing
  7. 假设是支付宝页面
  8. ==============
  9. 从缓存中获取了支付策略单例
  10. 假设是支付宝页面
  11. ==============
  12. 从缓存中获取了支付策略单例
  13. 假设是支付宝页面
  14. -------------
  15. 获取单例
  16. 缓存支付策略单例ing
  17. 假设是微信支付页面
  18. -------------
  19. 从缓存中获取了支付策略单例
  20. 假设是微信支付页面
  21. Process finished with exit code 0