目录

  1. 概述
  2. 类图
  3. 案例
  4. 总结
  5. 附录

概述

策略模式(Strategy Pattern)属于对象行为型模式,通过定义算法族,对每个算法的封装,最终使得不同算法可以相互替换,并且算法的变化不会影响使用算法的客户,此模式让算法的变化独立于使用算法的客户

❓为什么会存在策略模式?

软件开发中修改需求是常态,比如:今天让你设计一个求均值的算法,明天让你做一个求方差的算法,如果没有使用策略模式,每次设计完算法之后,都会造成算法调用方代码的修改,这并不符合开闭原则,所以策略模式就是想要做到:算法的变化并不会影响使用算法的客户(调用者)

✨策略模式中使用的设计原则:

  • 将变化的代码从不变的代码中分离出来;
  • 针对接口编程而不是具体类(定义策略接口);
  • 多用组合/聚合少用继承(客户通过组合方式使用策略)

类图

将策略模式具体表示在 UML 中,它的类图如下:
s

策略模式主要存在三个角色:

角色含义
环境(Context)持有一个策略类的引用,最终给客户端调用
抽象策略(Strategy)公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现
具体策略(Concrete Strategy)实现了抽象策略定义的接口,提供具体算法的实现

案例

设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为

1
2
3
4
//抽象策略
public interface QuackBehavior {
void quack();
}
1
2
3
4
5
6
7
//具体策略1
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("quack!");
}
}
1
2
3
4
5
6
7
//具体策略2
public class Squeak implements QuackBehavior{
@Override
public void quack() {
System.out.println("squeak!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//context类
public class Duck {
private QuackBehavior quackBehavior;

public void performQuack() {
if (quackBehavior != null) {
quackBehavior.quack();
}
}

public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test {
public static void main(String[] args) {
Duck duck = new Duck();
//切换到策略1
duck.setQuackBehavior(new Squeak());
//执行策略1的算法
duck.performQuack();
//切换到策略2
duck.setQuackBehavior(new Quack());
//执行策略2的算法
duck.performQuack();
}
}

总结

🤔策略模式的确非常强大,但是我们能在什么场景使用策略模式?

  • 使用策略模式可以避免使用多重条件语句,比如冗余的if...else语句或者switch...case语句
  • Spring 中的InstantiationStrategy使用了策略模式
  • 线程池的拒绝策略,使用了策略模式

😣策略模式并不是万能的,与其他设计模式相同,使用设计模式会增加代码的复杂性,策略模式中,每添加一个策略就要增加一个类,当策略过多时会导致类数目庞大不易管理

附录

行为型 - 策略(Strategy)