Strategy(策略)–对象行为型模式
一、意图
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
二、动机
1.在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂; 而且有时候支持不使用的算法也是一个性能负担。
2.如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
三、适用性
1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
2.需要使用一个算法的不同变体。例如,你可能会定义一些反应不同的空间、时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
3.算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
3.一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
四、结构
五、效果
1.相关算法系列。 Strategy类层次为Context定义了一系列的可供重用的算法。继承有利于析取出这些算法中的公共功能。
2.一个替代继承的方法。 继承提供了另一种支持多种算法或行为的方法。你可以直接生成一个Context类的子类,从而给它以不同的行为。但这会将行为硬行编制到Context中,而将算法的实现与Context的实现混合起来,从而使Context难以理解,难以维护和难以扩展,而且还不能动态的改变算法。最后得到一堆相关的类,它们之间唯一的差别就是它们所使用的算法或行为。将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、易于理解、易于扩展。
3.消除了一些条件语句。 Strategy模式提供了用条件语句选择所需的行为以外的另一种选择。当不同的行为堆砌在一个类中时。很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的Strategy类中消除了这些条件语句。
4.实现的选择。 Strategy模式可以提供相同行为的不同实现。客户可以根据不同的时间、空间权衡取舍要求不同策略中进行选择。
5.客户必须了解不同的Strategy。 本模式有一个潜在的缺点,就是客户要选择一个合适的Strategy九必须知道这些Strategy到底有何不同。此时可能不得不向客户暴露具体的实现问题。因此仅当这些不同行为变体与客户相关的行为时,才需要使用Strategy模式。
6.Strategy和Context之间的通信开销。 无论各个Concrete Strategy实现的算法是简单还是复杂,他们都共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的Concrete Strategy可能不是用呢其中的任何信息!这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样问题,那么将需要在Strategy和Context之间进行紧密的耦合。
7.增加了对象的数目。 Strategy增加了一个应用的对象数目。有时你可以将Strategy实现为可供各Context共享的无状态对象来减少这一个开销。任何其余的状态都由Context维护。Context在每一次对Strategy对象的请求中都将这个状态传递过去。共享的Strategy不应在各次调用之间维护状态。
六、实现
1.定义Strategy和Context接口。
2.将Strategy作为模板参数。
3.使Strategy对象成为可选的。
七、要点总结
1.Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
2.Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
3.如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
八、相关模式
Flyweight:Strategy对象经常是很好的轻量级对象。
九、举例说明
解一个方程可有多种方法,每个方法都是一种策略。
本文为李建忠设计模式视频的笔记以及《设计模式-可复用面向对象的软件的基础》和自己的部分见解