python 实现 策略模式

本文的目录地址

本文的代码地址

大多数问题都可以使用多种方法来解决。以排序问题为例,对于以一定次序把元素放入一个列表,排序算法有很多。通常来说,没有公认最适合所有场景的算法。一些不同的评判标准能帮助我们为不同的场景选择不同的排序算法,其中应该考虑的有以下几个。

  • 需要排序的元素数量
  • 算法的最佳、平均、最差时间复杂度
  • 算法的空间复杂度
  • 算法的稳定性
  • 算法的代码实现复杂度

可能还有更多的评判标准值得考虑,但重要的是,我们真的只能使用单个排序算法来应对所有情况吗?答案当然不是。一个更好的方案是把所有排序算法纳为己用,然后使用上面提到的标准针对当前情况选择最好的算法。这就是策略模式的目的。

策略模式(Strategy pattern)鼓励使用多种算法来解决一个问题,其杀手级特性是能够在运行时透明地切换算法(客户端代码对变化无感知)。因此,如果你有两种算法,并且知道其中一种对少量输入效果更好,另一种对大量输入效果更好,则可以使用策略模式在运行时基于输入数据决定使用哪种算法。

软件的例子

Python的sorted()和list.sort()函数是策略模式的例子。两个函数都接受一个命名参数key,这个参数本质上是实现了一个排序策略的函数的名称。

下面的例子(代码文件langs.py)展示了如何用以下方式使用两种不同的策略对编程语言进行排序:基于名称;基于流行度。

顺便说明一下pprint和attrgetter模块。pprint模块用于美化输出一个数据结构,attrgetter用于通过属性名访问class或namedtuple的属性。也可以使用一个lambda函数来替代使用attrgetter,但我觉得attrgetter的可读性更高。

import pprint
from collections import namedtuple
from operator import attrgetter

if __name__ == '__main__':
    ProgrammingLang = namedtuple('ProgrammingLang', 'name ranking')
    stats = (('Ruby', 14), ('JavaScript', 8), ('Python', 7),
             ('Scala', 31), ('Swift', 18), ('Lisp', 23))
    lang_stats=[ProgrammingLang(n,r) for n,r in stats]
    pp=pprint.PrettyPrinter(indent=5)
    pp.pprint(sorted(lang_stats,key=attrgetter('name')))
    print()
    pp.pprint(sorted(lang_stats,key=attrgetter('ranking')))

运行输出如下

[    ProgrammingLang(name='JavaScript', ranking=8),
     ProgrammingLang(name='Lisp', ranking=23),
     ProgrammingLang(name='Python', ranking=7),
     ProgrammingLang(name='Ruby', ranking=14),
     ProgrammingLang(name='Scala', ranking=31),
     ProgrammingLang(name='Swift', ranking=18)]

[    ProgrammingLang(name='Python', ranking=7),
     ProgrammingLang(name='JavaScript', ranking=8),
     ProgrammingLang(name='Ruby', ranking=14),
     ProgrammingLang(name='Swift', ranking=18),
     ProgrammingLang(name='Lisp', ranking=23),
     ProgrammingLang(name='Scala', ranking=31)]

应用案例

策略模式是一种非常通用的设计模式,可应用的场景很多。一般来说,不论何时希望动态、透明地应用不同算法,策略模式都是可行之路。这里所说不同算法的意思是,目的相同但实现方案不同的一类算法。这意味着算法结果应该是完全一致的,但每种实现都有不同的性能和代码复杂性(举例来说,对比一下顺序查找和二分查找)。

策略模式并不限于排序问题,也可用于创建各种不同的资源过滤器(身份验证、日志记录、数据压缩和加密等)。

策略模式的另一个应用是创建不同的样式表现,为了实现可移植性(例如,不同平台之间断行的不同)或动态地改变数据的表现。

另一个值得一提的应用是模拟;例如模拟机器人,一些机器人比另一些更有攻击性,一些机器人速度更快,等等。机器人行为中的所有不同之处都可以使用不同的策略来建模。

实现

关于策略模式的实现没有太多可说的。在函数非一等公民的语言中,每个策略都要用一个不同的类来实现。在Python中,我们可以把函数看作是普通的变量,这就简化了策略模式的实现。

假设我们要实现一个算法来检测在一个字符串中是否所有字符都是唯一的。 提供了两种策略:allUniqueSort和allUniqueSet。这两种策略各有利弊,在用户调用时由 allUnique函数进行无缝切换。完整代码见文件strategy.py。运行结果如下:

Insert word(type quit to exit)>hello
allUnique:(hello): False
Insert word(type quit to exit)>am
allUnique:(am): True
Insert word(type quit to exit)>message
allUnique:(message): False


猜你喜欢

转载自blog.csdn.net/hbu_pig/article/details/80930375