策略模式是一种行为设计模式。
策略模式定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。使算法的变化独立于使用它们的客户端。
- 想使用对象中各种不同的算法变体,并希望能在运行时切换算法。
- 将类的业务逻辑与其算法实现隔离开。
- 有许多仅在执行某些行为时略有不同的相似类。
- 当类中使用了复杂条件运算符以在同一算法的不同变体中切换(冗长的分支判断)。
- ...
优点:
- 可以在运行时切换对象内的算法。
- 可以将算法的实现和使用算法的代码隔离开来。
- 可以使用组合来代替继承。
- 开闭原则:无须修改上下文即可引入新策略。
缺点:
- 复杂度增加。
- 客户端必须知晓策略间的不同。
- 装饰模式可让你更改对象的外表,策略模式则让你能够改变其本质。
- 模板方法模式与策略模式:
- 模板方法基于继承机制:它允许通过扩展子类中的部分内容来改变部分算法。
- 策略基于组合机制:可以通过对相应行为提供不同的策略来改变对象的部分行为。
- 模板方法在类层次上运作,因此它是静态的。
- 策略在对象层次上运作,因此允许在运行时切换行为。
- 观察者模式是解耦观察者和被观察者。策略模式跟两者类似,它解耦的是策略的定义、创建、使用这三部分。
- 声明该算法所有变体的通用策略接口。
- 将算法逐一抽取到各自的类中,它们都必须实现策略接口。
- 在上下文类中添加一个成员变量用于保存对于策略对象的引用。然后提供设置器以修改该成员变量。
- 上下文仅可通过策略接口同策略对象进行交互。
- 如有需要还可定义一个接口来让策略访问其数据。
Java 8 开始支持 lambda 方法, 它可作为一种替代策略模式的简单方式。
策略接口
public interface Strategy {
// 声明该算法所有变体的通用策略接口。
void evict();
}
策略实现
public class StrategyFIFO implements Strategy {
// 将算法逐一抽取到各自的类中,它们都必须实现策略接口。
@Override
public void evict() {
System.out.println("使用【先进先出】策略进行丢弃");
}
}
public class StrategyLRU implements Strategy {
@Override
public void evict() {
System.out.println("使用【最近最久未使用】策略进行丢弃");
}
}
public class StrategyLFU implements Strategy {
@Override
public void evict() {
System.out.println("使用【最近最少使用】策略进行丢弃");
}
}
Context 上下文
public class Cache {
private Map cacheData = new HashMap<>();
// 在上下文类中添加一个成员变量用于保存对于策略对象的引用。
private Strategy evictionStrategy;
// 提供设置器以修改该成员变量。
public void setEvictionStrategy(Strategy evictionStrategy) {
this.evictionStrategy = evictionStrategy;
}
// 通过策略接口同策略对象进行交互
public void evict() {
evictionStrategy.evict();
}
public void add(String value) {
// ...
}
public String get() {
// ...
return null;
}
}
测试代码
public class StrategyTest {
@Test
public void test() {
Cache cache = new Cache();
cache.add("添加");
cache.add("缓存");
cache.add("数据");
cache.setEvictionStrategy(new StrategyFIFO());
cache.get();
cache.evict();
cache.evict();
cache.setEvictionStrategy(new StrategyLRU());
cache.evict();
cache.setEvictionStrategy(new StrategyLFU());
cache.evict();
}
}
java.util.Comparator 是策略接口类
Comparator.compare() 是策略方法
Collections.sort(List list, Comparator c) 调用自定义策略