【设计模式】策略模式

265 阅读4分钟

本文主要介绍策略模式的概念和用法。

模式背景

当实现某一个功能有多条途径,每种途径都对应一种逻辑或者算法,如何灵活的来实现途径的选择,就可以使用策略模式。

比如我们使用地图导航软件去某地的时候,有公交路线,自行车路线,地铁,步行等路线。每一个路线都对应着一个执行策略,这些策略都有用,在不同的场景下我们会选择不同的策略。所以如何去管理和使用这些策略是策略模式要解决的问题。我们总不能使用if-else啥的全塞在一个地方去判断。那是面向过程的写法。

定义&概念

**策略模式(Strategy):**定义一系列算法,将每一个算法都封装起来,并让他们可以互相替换。策略模式是一种对象行为型模式。

原理

策略模式是一种很简单且容易使用的设计模式。策略模式主要是对算法的封装,让不同的算法委托给不同的对象去管理。首先我们肯定希望算法可以扩展,然后希望客户端对算法的使用可以松耦合。所以策略模式响应的提供了2个元素:Context类抽象策略类

组成要素

  • 环境类(Context)
    • 用来操作策略的上下文环境。它是客户端和具体策略之间的解耦层,它内部引用了一个抽象策略,客户端通过他来执行具体的策略。
    • 之所以需要这个Context,还因为有可能我们执行一个具体的逻辑,是需要多个策略来配合的,这样这多个策略的执行逻辑,就可以放在Context类中,而不是耦合在客户端代码中。
  • 抽象策略类(Strategy)
    • 策略的抽象,就是为了方便扩展策略类,以及外部可以面向抽象编程。
  • 具体策略类(ConcreteStrategy)
    • 具体的策略实现。

对于如何指定策略,之所以需要将不同的策略拆分到不同的类中,就是可以让我们通过使用外部配置文件的方式,配置指定的策略。然后利用Java的反射和多态特性动态为其创建具体的策略类对象

UML

乍一看,我靠!这UML不和状态模式一德行吗?确实UML上是那么回事,他们本身解决问题思想也很相近,只是他们的服务目标不同,策略模式更重策略,状态模式更重状态,我个人感觉状态模式应该是策略模式的一种特殊情况(真的就只是个人感觉哈)。

实现

抽象策略类

public interface Strategy {
    void algorithm();
}

具体策略类

public class ConcreteStrategyA implements Strategy {
    @Override
    public void algorithm() {
        System.out.println("use A");
    }
}

环境类

public class Context {
    /**
     * 具体策略的引用
     */
    private Strategy strategy;

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        this.strategy.algorithm();
    }
}

使用(可以使用配置文件的方式指定策略)

public static void main(String[] args) {
    Context context = new Context();
    context.setStrategy(new ConcreteStrategyA());
    context.execute();
    context.setStrategy(new ConcreteStrategyB());
    context.execute();
}

优缺点

优点

  • 完美支持开闭原则,可以无修改的添加和替换算法(使用配置指定策略的情况下)。
  • 可以减少系统的大量的臃肿的if-else

缺点

  • 策略类数量会增多,每个策略都是一个类,复用的可能性很小,任何一个细小的变化可能都需要添加一个新的策略类。
  • 没法支持使用某个策略类的一部分,然后再使用另一个策略类的场景。

使用场景

  • 系统对某个目标实现,有很多算法的场景。
  • 算法需要自由切换的场景。
  • 想要屏蔽算法具体规则的场景。

总结

策略模式就比较简单了,你知道知道多态,可能自己在开发中自己就已经使用了策略模式了。策略模式核心点就是抽象策略类和环境类。我们使用的时候,其实主要就设计好抽象策略类就行了。一个好的抽象策略类是一个优秀策略模式的关键。

相关代码:github.com/zhaohaoren/…

如有代码和文章问题,还请指正!感谢!