java使用策略模式(进阶篇)

这篇具有很好参考价值的文章主要介绍了java使用策略模式(进阶篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

介绍

策略模式是一个非常简单且常用的设计模式,策略模式最常见的作用就是解决代码中冗长的 if-else 或 switch 分支判断语句。
本文后半部分应该会让熟悉策略模式的同学也会有一些收获。本文重点在于笔者阅读 Flink 源码过程中发现了一个设计比较巧妙的点,可以对策略模式进行优化,所以特意写篇文章总结输出一下。
本文主要讲述:

  • 什么场景需要使用策略模式,即:策略模式的作用,策略模式解决了什么问题
  • 策略模式的定义和使用
  • 策略工厂类中,如果每次都要返回新的策略对象,怎么优化 if-else 分支判断逻辑?

什么场景需要使用策略模式?

// 根据 type 的不同,执行不同分支的代码逻辑,
private void process(String type){
  if(type == "A"){
    // 执行一大堆 A 类型的代码逻辑

  } else if (type == "B") {
    // 执行一大堆 B 类型的代码逻辑

  } else if (type == "C") {
    // 执行一大堆 C 类型的代码逻辑

  } else {
    // 上述都没有匹配成功,执行默认的代码逻辑,
    // 或者抛出异常打印错误日志等
  }
}

策略模式的定义和使用

策略模式的定义

策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
翻译成中文就是:定义一组算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

经上述分析,笔者认为策略模式可以达到这样的效果:假设 A 类调用 B 类,那么可以认为 A 类是 B 类的客户端,当 B 类增加了一些策略时,客户端 A 类不用进行任何的代码改动即可使用新策略。
策略模式的使用包含三部分:策略的定义、创建和使用。

策略的定义

策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。

public interface Strategy {
  void algorithmInterface();
}

public class ConcreteStrategyA implements Strategy {
  @Override
  public void  algorithmInterface() {
    //具体的算法...
  }
}

public class ConcreteStrategyB implements Strategy {
  @Override
  public void  algorithmInterface() {
    //具体的算法...
  }
}

如上述代码所示,定义了一个策略接口 Strategy,具体的策略实现类都实现 Strategy 接口,并重写 algorithmInterface 方法,最后客户端根据不同的策略即可调用不同实现类的 algorithmInterface 方法。

策略的创建

可以将创建策略的代码逻辑抽象到工厂类中,提前在工厂类创建好所有策略类,缓存在 Map 中。Map 的 key 为策略类型,value 为具体的策略实现类。当需要使用策略时根据 type 去 Map 中 get 即可获取到相应的策略实现类。

public class StrategyFactory {
  // Map 的 key 为策略类型,value 为具体的策略实现类
  private static final Map<String, Strategy> strategies = new HashMap<>();

  // 提前创建好所有策略类,缓存到 Map 中
  static {
    strategies.put("A", new ConcreteStrategyA());
    strategies.put("B", new ConcreteStrategyB());
  }

  // 需要使用策略时根据 type 去 Map 中 get 即可获取到相应的策略实现类
  public static Strategy getStrategy(String type) {
    if (type == null || type.isEmpty()) {
      throw new IllegalArgumentException("type should not be empty.");
    }
    return strategies.get(type);
  }
}

这里重点在于使用”查表法”代替了大量的分支判断,即每次根据 type 去 Map 中获取,省略了大量的 if-else。

策略的使用

具体使用 A、B、C 何种策略,在具体的场景,可以会根据系统的配置来选择。可以从配置文件中读取出配置,然后传递给策略工厂类 StrategyFactory 的 getStrategy 方法即可获取到相应的策略类。最后调用策略类的 algorithmInterface 方法去执行代码逻辑。
代码如下所示,省略了从配置文件中读取配置的流程。

// 根据 type 的不同,执行不同分支的代码逻辑,
private void process(String type){
 Strategy strategy = StrategyFactory.getStrategy(type);
  // 调用策略类的 algorithmInterface 方法去执行代码逻辑
  strategy.algorithmInterface();
}

当前设计是否容易扩展性

最原始的 process 方法中,首先会判断各种 type,然后执行不同类型的代码逻辑。如果需要扩展新的 D、E、F 类型,需要大量修改 process 方法。

优化后,如果需要扩展新的 D、E、F 类型,流程如下:

  • 定义相应的 D、E、F 类型的策略实现类
  • 提前在策略工厂类 StrategyFactory 中创建相应的策略实现类,并添加到 Map 中
  • 客户端代码不用进行任何改动,即:process 方法不需要进行改动

优化后的代码相对来说职责更加单一,且对调用方非常友好。调用方代码不需要任何改动即可使用新的策略。要做的可能就是在配置文件中配置新的策略即可。

到这里,策略模式的基本知识就讲完了。

有状态的策略类不能提前创建

在策略类的创建部分,在类初始化时,将所有的策略类提前创建好,存放在 Map 中。当需要使用策略时根据 type 去 Map 中 get 即可获取到相应的策略实现类。

假设策略类是有状态的,每次获取策略对象时,都要求创建新的策略类。此时,就不能使用 Map 缓存的方式来优化代码结构了。可以使用如下方式实现策略工厂类:

public class StrategyFactory {
  public static Strategy getStrategy(String type) {
    if (type == null || type.isEmpty()) {
      throw new IllegalArgumentException("type should not be empty.");
    }

    if (type.equals("A")) {
      return new ConcreteStrategyA();
    } else if (type.equals("B")) {
      return new ConcreteStrategyB();
    }

    return null;
  }
}

上述代码又退化回了 if-else 嵌套,当然也可以优化为 switch-case 的设计。
在策略工厂类中,如果每次都要返回新的策略对象,我们还是需要在工厂类中编写 if-else 分支判断逻辑,那这个问题该如何解决呢?
笔者看到文末大家的回答,点赞数最高的评论是:仍然可以用查表法,只不过存储的不再是实例,而是class,使用时获取对应的class,再通过反射创建实例。
反射在这里应该是可以实现,但是笔者感觉不是非常灵活,假设策略实现类需要在这里调用一些有参构造器,且不同的策略类的有参构造器需要传入的参数不同,那么反射实现起来不是非常灵活。
例如 ConcreteStrategyA 的构造器需要传入 age,ConcreteStrategyB 的构造器需要传入 date。对于这样的 case,反射不太好实现,如果实现出来,也是一对 if-else 分支判断。
文末也没有其他令笔者眼前一亮的回答,反倒是笔者在阅读 Flink 源码的过程中,发现了一个笔者感觉比较优秀的解决方案;

策略优化

首先分析一个问题来源:

  • 对于无状态的策略类,将所有的策略类提前创建好,存放在 Map 中。当需要使用策略时根据 type 去 Map 中 get 即可获取到相应的策略实现类。
  • 对于有状态的策略类,不能提前创建所有的策略类,所以没办法提前创建好将其存放在 Map 中

换种思路:

  • 给每个具体的策略类创建相应的策略类工厂。例如 ConcreteStrategyA 的工厂为 StrategyFactoryA, ConcreteStrategyB 的工厂为 StrategyFactoryB。
  • 虽然没办法提前创建好策略类放到 Map 中,但是可以将策略类的工厂类提前创建好放到 Map 中。根据传入的 type 就可以从 Map 中获取相应策略类的工厂类,然后执行工厂类的 create 方法即可创建出相应的策略类。

根据上述思路,实现相应代码。
首先定义策略工厂接口,并分别实现策略 A 和策略 B 的工厂类:

// 策略工厂接口
public interface StrategyFactory {
  Strategy create();
}

// 策略 A 的工厂类,用于创建策略 A
public class StrategyFactoryA implements StrategyFactory{
    @Override
    public Strategy create() {
        return new ConcreteStrategyA();
    }
}

// 策略 B 的工厂类,用于创建策略 B
public class StrategyFactoryB implements StrategyFactory{
    @Override
    public Strategy create() {
        return new ConcreteStrategyB();
    }
}

对外开放的工厂实现如下:

public class Factory {

    // Map 的 key 为策略类型,value 为 策略的工厂类
    private static final Map<String, StrategyFactory> 
      STRATEGY_FACTORIES = new HashMap<>();

    static {
       // 将各种实现类的工厂提前创建好放到 Map 中
        STRATEGY_FACTORIES.put("A", new StrategyFactoryA());
        STRATEGY_FACTORIES.put("B", new StrategyFactoryB());
    }

    public static Strategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        // 根据 type 获取对应的策略工厂
        StrategyFactory strategyFactory = STRATEGY_FACTORIES.get(type);
       // 调用具体工厂类的 create 方法即可创建出相应的策略类
        return strategyFactory.create();
    }
}

Factory 类中定义了 Map,Map 的 key 为策略类型,value 为 策略的工厂类。Factory 类初始化时,将各种实现类的工厂提前创> 建好放到 Map 中。

Factory 类的静态方法 getStrategy 用于根据 type 创建相应的策略类,getStrategy 方法根据 type 从 Map 中获取 type 对应的策略类的工厂,调用具体工厂类的 create 方法即可创建出相应的策略类。

当策略类的构造方法比较复杂也没关系,封装在策略类相应的工厂中即可。

旧方案对于每次要创建新策略类的场景,要搞一堆 if-else 分支判断,上述流程使用 Map 优化了 if-else 分支判断逻辑。但带来了一个新的问题,即:创建出了很多类,相比之前的实现来讲,多了 StrategyFactoryA 和 StrategyFactoryB 类。

为了代码的简洁,可以利用 Java8 的 lambda 表达式将 StrategyFactoryA 和 StrategyFactoryB 类优化掉。截取上述部分代码实现:

// 策略工厂接口
public interface StrategyFactory {
  Strategy create();
}

// 策略 A 的工厂类,用于创建策略 A
public class StrategyFactoryA implements StrategyFactory{
    @Override
    public Strategy create() {
        return new ConcreteStrategyA();
    }
}

Map<String, StrategyFactory> STRATEGY_FACTORIES = new HashMap<>();
// 将各种实现类的工厂提前创建好放到 Map 中
STRATEGY_FACTORIES.put("A", new StrategyFactoryA());

上述代码使用 lambda 优化后:

// 策略工厂接口
public interface StrategyFactory {
  Strategy create();
}

Map<String, StrategyFactory> STRATEGY_FACTORIES = new HashMap<>();
// 将各种实现类的工厂提前创建好放到 Map 中
STRATEGY_FACTORIES.put("A", () -> new ConcreteStrategyA());

关于 lambda 这里就不多解释了。lambda 表达式还能优化为 Java8 的方法引用,代码如下所示:

STRATEGY_FACTORIES.put(“A”, ConcreteStrategyA::new);

最后

把上述整个代码的最终版贴在这里:

// 策略工厂接口
public interface StrategyFactory {
  Strategy create();
}

public class Factory {

    // Map 的 key 为策略类型,value 为 策略的工厂类
    private static final Map<String, StrategyFactory> 
      STRATEGY_FACTORIES = new HashMap<>();

    static {
       // 将各种实现类的工厂提前创建好放到 Map 中
        STRATEGY_FACTORIES.put("A", ConcreteStrategyA::new);
        STRATEGY_FACTORIES.put("B", ConcreteStrategyB::new);
    }

    public static Strategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        // 根据 type 获取对应的策略工厂
        StrategyFactory strategyFactory = STRATEGY_FACTORIES.get(type);
       // 调用具体工厂类的 create 方法即可创建出相应的策略类
        return strategyFactory.create();
    }
}

代码量相比之前的策略类可以共享的代码设计来讲,只是增加了一个 StrategyFactory 接口的设计,所以整体代码也是非常简洁的。
原文链接:https://guosmilesmile.github.io/2020/07/05/Flink%E4%B8%AD%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/文章来源地址https://www.toymoban.com/news/detail-790940.html

到了这里,关于java使用策略模式(进阶篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java8里如何使用流?《Java8 实战》读书笔记 第 5 章 使用流

    [实践总结] java8 展平嵌套数组 [实践总结] java8 列表根据元素属性去重 [实践总结] String,int[],Integer[],List<Integer>互转 [实践总结] String,String[],List<String>互转 [实践总结] String,int,Integer互转 ✅ Further Reading : java8 数值流介绍 ✅ Further Reading : java8 构建流的5种方法

    2024年02月16日
    浏览(34)
  • Windows11配置Java8开发环境 - JDK1.8

    1、下载JDK 我们要下载的是Oracle版本的JDK,我们首先进入Oracle的官网的Java下载页面:https://www.oracle.com/cn/java/technologies/downloads/ 一直往下滑 ,找到 Java8 —点击 Windows (如果你是其他系统选择你对应的系统即可)— 在下方根据你的电脑系统类型选择对应的X86或X64然后点击下载

    2024年02月10日
    浏览(45)
  • java8-使用流-2

    筛选各异的元素 流还支持一个叫作aistinct的方法,它会返回一个元素各异(根据流所生成元素的hashcode和eguals方法实现)的流。例如,以下代码会筛选出列表中所有的偶数,并确保没有重复。图5-2直观地显示了这个过程。 5.1.3截短流 流支持Limit(n)方法,该方法会返回一个不超过给

    2024年02月20日
    浏览(40)
  • java设计模式---策略模式

    策略设计模式是一种行为设计模式。当在处理一个业务时,有多种处理方式,并且需要再运行时决定使哪一种具体实现时,就会使用策略模式。 策略模式的类图: 在支付业务中,有三种付款方式,程序运行时使用哪种方式由用户选择,根据用户选择执行不同的逻辑。 首先,

    2024年02月10日
    浏览(43)
  • Java设计模式——策略模式

    1. 策略模式简介 策略模式: 策略模式是一种行为型模式, 它将对象和行为分开, 将行为定义为一个行为接口和具体行为的实现 策略模式最大的特点是行为的变化, 行为之间可以相互替换 每个if判断都可以理解为一个策略. 本模式是的算法可独立于使用它的用户而变化 2. 模式结构

    2024年02月11日
    浏览(49)
  • Java特性之设计模式【策略模式】

    概述 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法 主要解决 :在有多种

    2024年02月08日
    浏览(53)
  • Java设计模式之策略模式详解

    大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天,让我们一同踏入Java设计模式之策略模式的世界,探讨代码中的智慧抉择。 策略模式的核心思想 策略模式是一种行为型设计模式,它定义了算法家族

    2024年01月20日
    浏览(46)
  • Java8的新特性以及使用

    1.   通 过 1 0 个示 例 来 初 步认 识 J a v a 8 中 的 l a m bd a 表达 式   我个 人 对 J a v a   8 发 布 非 常 激动 , 尤 其 是 l a m b d a 表 达式 和 流 AP I 。 越 来 越 多 的 了解 它 们 , 我 能 写 出 更 干 净 的代 码 。 虽然 一 开 始 并 不 是 这 样 。 第一 次 看 到 用 la m b d a 表

    2024年02月07日
    浏览(46)
  • 从零开始搭建Springboot开发环境(Java8+Git+Maven+MySQL+Idea)

    所谓万事开头难,对于初学Java和Springboot框架的小伙伴往往会花不少时间在开发环境搭建上面。究其原因其实还是不熟悉,作为在IT界摸爬滚打数年的老司机,对于各种开发环境搭建已经了然于胸,自己当年也是这么过来的。 今天我就毕其功于一役,解放大家的时间,让凡人

    2024年04月17日
    浏览(81)
  • Java设计模式之策略(Strategy)模式

    策略(Strategy)设计模式定义了一系列算法,将它们封装起来,并且可以相互替换使用,从而使得算法可以独立于使用它的客户而变化。 策略(Strategy)设计模式是一种行为型设计模式,它允许在运行时动态地选择算法。策略模式将算法封装为算法族,从而可以在运行时根据

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包