策略模式

核心思想:把一系列算法逐个封装起来,使它们相互可替换 (interchangeable)

通过策略模式可以使算法和算法的调用者解耦合

 

策略模式解决的问题:

在传统的类继承体系中,代码的复用是从父类 -> 子类,即从根节点往子节点的,如下图所示

 

 我们将根节点标记为1,第一层子节点从左到右标记为2 和 3,第二层子节点从左到右标记为4 5 6 7

在这个示意图中,2和3是1的子类,4、5是2的子类,6、7是3的子类

考虑这样一个场景:类1中有A、B、C 3个方法,则此时2和3中由于继承关系,也有A、B、C 3个方法,若类2和类3需要不同于父类的实现,则需要在其内部进行Override

当类2和类3都需要实现一个不同的方法B,记为B',由于B'不同于B,所以肯定不能直接使用父类中的方法;但由于类2和类3不存在继承关系,就会出现一种现象,即B'必须在类2和类3中分别实现一次,而这两份代码完全相同!

进一步考虑:若1的子类不是2个,而是10个、20个,其中有5个类需要使用B'方法,或者不同于C的C'方法(但仍有剩余的其它子类需要B、C方法),那么是不是要将B'、C'的代码拷贝5遍、10遍呢?

至此可以发现一个问题,即在继承体系中,同一层级的不同类以及不同层级不存在祖先关系的类之间复用代码是极其困难的。而策略模式可以比较好地解决这个问题。

策略模式的 UML 图

策略模式解决这个问题的方式就是用组合代替继承。

每个类的行为由其对象成员决定,其成员是一个抽象的接口,具体行为由运行时其具体的子类决定;算法的具体实现在接口的子类中,如上图的OperationAdd、OperationSubstract等等,而Context中有一个Strategy的实例,这个实例具体是哪个子类,可以在运行时决定,在那之后调用doOperation()方法,执行的就是具体算法的代码

 

回到刚才的例子,B和B'是同一个算法的两个不同实现,将它们作为同一个abstract interface的子类,需要具有该算法的类,就持有一个该interface的对象,若在运行时该类需要使用B算法,则将该对象赋值为B;若运行时需要使用B‘,则将该对象赋值为B'。其它代码和后续调用的代码都可以保持不变。同时,在这种情况下,算法的调用者和算法的具体实现也是解耦合的。

 

参考:

策略模式