喜欢就关注桃子的学习笔记吧!
前言
在设计模式的导言中我们就将23种常见的设计模式分为了三类:创建型模式、行为模式以及结构型模式。在前面的内容中也介绍了「工厂模式」和「抽象工厂模式」,这两者均是创建型模式,今天我们介绍一种新的模式,行为模式--「策略模式」。为什么在第三篇就介绍这个模式,是因为策略模式在某些程度上和工厂模式有点相似,为了加深印象以及更好的形成的对比,所以在今天介绍策略模式。
策略意图
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
别名
政策(Policy)
案例
小李开工厂赚了钱,但是随着工厂越来越多,每次去工厂经常绕路,为了解决这个问题,小李决定让人开发一款导航的APP,核心功能就是为他提供路线规划,输入工厂地址后,能够在地图上显示最快的路线。
程序的第一版本规划出了公路路线,小李开着车感觉很不错,但是不久小李就发现一个问题了,有时候两个工厂很近,程序竟然规划公路路线的距离变远了,显然这样子不行,于是让程序加入了步行路线,好景不长,有的工厂之间出现了步行太远,公路又绕行的情况,只好加入骑行路线。随着时间的推移,各种各样的路线规划被加入到软件当中去了。
软件的功能越来越多,但是代码的体积也越来越多,所有的路线规划算法都集中在一个类中,团队成员维护算法的难度与日俱增,有时候修复简单的问题,对某个算法修改都会导致整个类出现问题,实现新功能时,团队成员需要修改同一个类,经常会造成冲突,问题急需解决。
解决方案
主要问题就是因为所有的路线规划算法都在集中在一个类中,所以我们可以将不同路线规划算法归结到一组成为「策略」的独立类中。
然后在**上下文(Context)**的类中,通过一个成员变量保持对每种策略的引用。上下文不负责选择对应的策略,由客户端将所需的策略传递给上下文。这样子做的好处就是,上下文可以独立于具体策略,我们可以在不修改上下文代码或者其他策略情况下添加新的算法或修改已有的算法了。
UML 图

代码
最后让我们通过代码去实现它。
# encoding:utf-8
from abc import ABC, abstractmethod
from typing import List
# 策略
class Strategy(ABC):
@abstractmethod
def do_algorithm(self, data: List):
pass
# 具体策略
class ConcreteStrategyA(Strategy):
def do_algorithm(self) -> None:
print('ConcreteStrategyA do algorithm')
class ConcreteStrategyB(Strategy):
def do_algorithm(self) -> None:
print('ConcreteStrategyB do algorithm')
# 上下文
class Context():
def __init__(self, strategy: Strategy) -> None:
self._strategy = strategy
@property
def strategy(self) -> Strategy:
return self._strategy
@strategy.setter
def strategy(self, strategy: Strategy) -> None:
self._strategy = strategy
def do_something(self) -> None:
self._strategy.do_algorithm()
if __name__ == "__main__":
context = Context(ConcreteStrategyA())
context.do_something()
context.strategy = ConcreteStrategyB()
context.do_something()
看一下运行结果:
ConcreteStrategyA do algorithm
ConcreteStrategyB do algorithm
总结
应用场景
当你想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时, 可使用策略模式。 当你有许多仅在执行某些行为时略有不同的相似类时, 可使用策略模式。 如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时, 可使用该模式。
优缺点
优点
自由切换对象内的算法。 避免使用多重条件判断。 组合代替继承。 开闭原则。你无需对上下文进行修改就能够引入新的策略,即拓展性良好。
缺点
策略类会增多。 所有策略类都需要对外暴露,即客户端必须知晓策略间的不同——它需要选择合适的策略。
往期推荐









