🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 策略模式 *策略模式* 看起来像是从同一个基类继承而来的一系列 *命令* 类。但是仔细查看 *命令模式*,你就会发现它也具有同样的结构:一系列分层次的 *函数对象*。不同之处在于,这些函数对象的用法和策略模式不同。就像前面的 `io/DirList.java` 那个例子,使用 *命令* 是为了解决特定问题 -- 从一个列表中选择文件。“不变的部分”是被调用的那个方法,而变化的部分被分离出来放到 *函数对象* 中。我认为 *命令模式* 在编码阶段提供了灵活性,而 *策略模式* 的灵活性在运行时才会体现出来。尽管如此,这种区别却是非常模糊的。 另外,*策略模式* 还可以添加一个“上下文(context)”,这个上下文(context)可以是一个代理类(surrogate class),用来控制对某个特定 *策略* 对象的选择和使用。就像 *桥接模式* 一样!下面我们来一探究竟: ```java // patterns/strategy/StrategyPattern.java // {java patterns.strategy.StrategyPattern} package patterns.strategy; import java.util.function.*; import java.util.*; // The common strategy base type: class FindMinima { Function<List<Double>, List<Double>> algorithm; } // The various strategies: class LeastSquares extends FindMinima { LeastSquares() { // Line is a sequence of points (Dummy data): algorithm = (line) -> Arrays.asList(1.1, 2.2); } } class Perturbation extends FindMinima { Perturbation() { algorithm = (line) -> Arrays.asList(3.3, 4.4); } } class Bisection extends FindMinima { Bisection() { algorithm = (line) -> Arrays.asList(5.5, 6.6); } } // The "Context" controls the strategy: class MinimaSolver { private FindMinima strategy; MinimaSolver(FindMinima strat) { strategy = strat; } List<Double> minima(List<Double> line) { return strategy.algorithm.apply(line); } void changeAlgorithm(FindMinima newAlgorithm) { strategy = newAlgorithm; } } public class StrategyPattern { public static void main(String[] args) { MinimaSolver solver = new MinimaSolver(new LeastSquares()); List<Double> line = Arrays.asList( 1.0, 2.0, 1.0, 2.0, -1.0, 3.0, 4.0, 5.0, 4.0 ); System.out.println(solver.minima(line)); solver.changeAlgorithm(new Bisection()); System.out.println(solver.minima(line)); } } /* Output: [1.1, 2.2] [5.5, 6.6] */ ``` `MinimaSolver` 中的 `changeAlgorithm()` 方法将一个不同的策略插入到了 `私有` 域 `strategy` 中,这使得在调用 `minima()` 方法时,可以使用新的策略。 我们可以通过将上下文注入到 `FindMinima` 中来简化我们的解决方法。 ```java // patterns/strategy/StrategyPattern2.java // {java patterns.strategy.StrategyPattern2} package patterns.strategy; import java.util.function.*; import java.util.*; // "Context" is now incorporated: class FindMinima2 { Function<List<Double>, List<Double>> algorithm; FindMinima2() { leastSquares(); } // default // The various strategies: void leastSquares() { algorithm = (line) -> Arrays.asList(1.1, 2.2); } void perturbation() { algorithm = (line) -> Arrays.asList(3.3, 4.4); } void bisection() { algorithm = (line) -> Arrays.asList(5.5, 6.6); } List<Double> minima(List<Double> line) { return algorithm.apply(line); } } public class StrategyPattern2 { public static void main(String[] args) { FindMinima2 solver = new FindMinima2(); List<Double> line = Arrays.asList( 1.0, 2.0, 1.0, 2.0, -1.0, 3.0, 4.0, 5.0, 4.0 ); System.out.println(solver.minima(line)); solver.bisection(); System.out.println(solver.minima(line)); } } /* Output: [1.1, 2.2] [5.5, 6.6] */ ``` `FindMinima2` 封装了不同的算法,也包含了“上下文”(Context),所以它便可以在一个单独的类中控制算法的选择了。