本文主要介绍策略模式的概念和用法。
模式背景
当实现某一个功能有多条途径,每种途径都对应一种逻辑或者算法,如何灵活的来实现途径的选择,就可以使用策略模式。
比如我们使用地图导航软件去某地的时候,有公交路线,自行车路线,地铁,步行等路线。每一个路线都对应着一个执行策略,这些策略都有用,在不同的场景下我们会选择不同的策略。所以如何去管理和使用这些策略是策略模式要解决的问题。我们总不能使用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。
缺点
- 策略类数量会增多,每个策略都是一个类,复用的可能性很小,任何一个细小的变化可能都需要添加一个新的策略类。
- 没法支持使用某个策略类的一部分,然后再使用另一个策略类的场景。
使用场景
- 系统对某个目标实现,有很多算法的场景。
- 算法需要自由切换的场景。
- 想要屏蔽算法具体规则的场景。
总结
策略模式就比较简单了,你知道知道多态,可能自己在开发中自己就已经使用了策略模式了。策略模式核心点就是抽象策略类和环境类。我们使用的时候,其实主要就设计好抽象策略类就行了。一个好的抽象策略类是一个优秀策略模式的关键。
附
如有代码和文章问题,还请指正!感谢!