前言
本文聊聊 行为型模式中的策略模式。策略模式就是定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
UML
代码案例
// Strategy 策略接口,定义策略的抽象
public interface Strategy {
Integer discount(Integer money);
}
// 策略A
public class StrategyA implements Strategy {
@Override
public Integer discount(Integer money) {
return money / 10;
}
}
// 策略B
public class StrategyB implements Strategy {
@Override
public Integer discount(Integer money) {
return money - 20;
}
}
// Content 上下文类,持有具体策略类的实例,并负责调用相关的算法
public class StrategyContent {
// 包含一个策略
private Strategy strategy;
// 根据客户端传来的策略进行相应处理
public StrategyContent(Strategy strategy) {
this.strategy = strategy;
}
public Integer discount(Integer money) {
return this.strategy.discount(money);
}
}
// 测试
public class StrategyTest {
public static void main(String[] args) {
Strategy strategy = new StrategyA();
// 客户端将想要用的算法传入Content
StrategyContent strategyContent = new StrategyContent(strategy);
// 相应计算
System.out.println(strategyContent.discount(100));
}
}
源码中的应用
JDK中Arrays.sort(T[] a, Comparator<? super T> c)这个排序方法,它在内部实现了TimSort排序,但是,排序算法在比较两个元素大小的时候,需要借助我们传入的Comparator对象,才能完成比较。因此,这里的策略是指比较两个元素大小的策略,可以是忽略大小写比较,可以是倒序比较,也可以根据字符串长度比较。
如果我们想忽略大小写排序,就传入String::compareToIgnoreCase,如果我们想倒序排序,就传入(s1, s2) -> -s1.compareTo(s2),这个比较两个元素大小的算法就是策略。
优缺点
用户可以在不修改原有系统的基础上选择算法(策略),并且可以灵活地增加新的算法(策略)。符合开闭原则,对算法的开发。
但传统的策略模式实现方式中,客户端必须知道所有的具体策略类,并须自行显示决定使用哪一个策略类。
策略模式是将一系列的算法封装起来,让他们可以相互替换。可以避免一些if else 语句的处理,我们只需要在需要的场景下选择需要的策略。但是那些场景的判断时也是if else 来判断时,我们可以选择工厂模式来将"条件"进行封装,让我们只需要传入我们的条件来返回相应的策略。也就是策略和工厂的组合,策略也可以搭配单例返回同一个策略,不用过多的new对象了。
参考博客
- www.liaoxuefeng.com