设计模式 by Python1:策略模式

设计模式 by Python1:策略模式

最近开始重新看《Head First 设计模式》,作为一个不错的练习,打算在整理设计模式笔记的时候用Python实现。

作为第一个介绍的设计模式,策略模式简单的同时相当实用。

在这里,我不打算采用书中的鸭子作为例子,我决定使用我喜欢的军事题材来描述,我们不做鸭子,造航母!

航母游戏

我们现在考虑如何做一个航母游戏,就相当于航母版的战舰世界吧,这里只有一类船:航空母舰。

我们考虑一下,航母最重要的共能无疑是起降战机,目前世界上的现代航母,无非采用以下几种方式起降:

  • 弹射起飞阻拦着舰,比如美帝的尼米兹系列。
  • 滑跃起飞阻拦着舰,比如我们的辽宁舰。
  • 垂直起飞垂直着舰,比如阿三的几艘。
  • 滑跃起飞垂直着舰,不错,这么奇葩的只有我大嘤帝国。

其中起飞模式有三种,着舰模式有两种。

凡是学过OOP的,第一直觉肯定是构建一个这样的类图:

设计模式 by Python1:策略模式

这很容易想到,但是,这样做没有任何代码复用,我们需要在每个子类中分别实现起飞和着舰的内容,现在我们只是创建了四个子类,如果要加入日本、意大利、泰国之类的小航母,那无疑是场灾难。

代码复用的基石是将可可变且可复用的部分进行剥离和封装

这也是非常实用的一种设计模式准则。

如我们之前讨论的,起飞和降落都是有数的几种模式,那我们是不是可以将这些起飞、降落模式从具体的航母上剥离?

如果你是Java程序员,那肯定会想到接口。不错,我们可以通过接口将这几种起降模式进行剥离和封装。

设计模式 by Python1:策略模式

可能这个类图并不怎么美观,不过我已经尽了最大努力。

我们可以从类图上看到,我们已经把降落和起飞逻辑从航母具体实现中剥离,分别使用两组类来实现,然后再通过组合到航母基类的方式来使用这些起、降落模式。

我们现在用Python来具体实现。

代码有点多,这里就不一一展示了,工程文件直接上传到百度云:

链接:https://pan.baidu.com/s/1sGrKywSRwYEhbVr5fKg68w
提取码:1c4b
复制这段内容后打开百度网盘手机App,操作更方便哦

我们现在运行一下:

辽宁舰
进行滑跃起飞
进行阻拦着舰
尼米兹级
进行弹射起飞
进行阻拦着舰
伊丽莎白女王号
进行滑跃起飞
进行垂直降落着舰
维克拉马蒂亚号
进行垂直起飞
进行垂直降落着舰

可以看到不同类型的航母都按自己的方式起飞和着舰,而且无论新增哪个国家的哪艘航母,我们都可以按照已经构建的飞行和着舰模式进行快速构建。

而且这样做还有额外的好处,比如我们如果需要对辽宁号进行改造,安装弹射器,将起飞模式改为弹射起飞,我们只需要这样做:

在基类中加入改变起飞模式的方法:

    def setTakeoffMode(self, takeoffMode):
        self._takeoffMode=takeoffMode

然后修改主程序:

lnCarrier = LiaoNingCarrier()
print(lnCarrier)
from takeoff_pkg.catapult_takeoff import CatapultTakeoff
lnCarrier.setTakeoffMode(CatapultTakeoff())
lnCarrier.takeoff()
lnCarrier.land()

我们只需要更换辽宁号的起飞模式就能轻松实现。

总结一下,我们刚才进行的一系列OOP封装使用的就是一种设计模式,称为策略模式。

策略模式

顾名思义,策略模式指的是将一系列相似的策略封装为一组类,以起到复用的效果。

这里有三个关键的设计模式准则:

  • 抽取可变的部分进行封装。
  • 多用组合,少用继承。
  • 针对接口编程,而非实现。

这三点其实是互相关联的,比如我们如果要把一组类中的可复用部分进行封装,可以选择的手段只有继承和组合。而继承是一种很笨重的方式,一来它和子类紧密结合,而且随着继承层级的增加继承树就会很复杂,基类和各级别子类之间的重写继承关系就很难维护和处理。而组合就相当灵活,还可以随时替换。

而为了实现组合,那必然会用到接口或者抽象基类,针对组合这个场景来说,我们其实并不需要关心具体是用接口实现还是抽象基类,其本质都是利用你他们的多态特性持有相应的句柄,以进行多态调用。

而正是因为采用了接口编程的方式,我们才能把具体的策略实现和拥有策略的类松耦合。正是这样才能实现策略的复用和相应带来的灵活性。

不得不说用Python进行面向对象编程还是挺累的,这很不Python。

上一篇:Python1之continue,break语句


下一篇:python1