本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题:

  1. 为什么?即为什么要使用这个设计模式,在使用这个模式之前存在什么样的问题?
  2. 是什么?通过Python语言来去实现这个设计模式,用于解决为什么中提到的问题。
  3. 怎么用?理解了为什么我们也就基本了解了什么情况下使用这个模式,不过在这里还是会细化使用场景,阐述模式的局限和优缺点。

这一篇我们先来看看策略模式。

为什么?

假设我们有如下一个项目:

飞机大战游戏中,玩家可以选择A型飞机,也可以选择B型飞机,A型飞机可以发射穿甲弹,B型飞机可以发射速射弹

 
plane.png

好了,初看上去是不是很简单,也很容易想到可以用继承来解决代码复用的问题,好吧,talk is cheap, show me the code!

# Plane作为所有种类的飞机的父类
class Plane(object):
def __init__(self):
self.color = black
self.life_left = 100 def fire():
pass def turn(direction):
"""用于实现飞机的转向"""
...

有了父类我们可以考虑造A型飞机和B型飞机了

class ATypePlane(Plane):
def __init__(self):
super(ATypePlane, self).__init__() def fire():
... #这里实现穿甲弹射击 class BTypePlane(Plane):
def __init__(self):
super(BTypePlane, self).__init__() def fire():
... #这里实现速射弹射击

接下来你可能会在很多场景使用这两个类,如下

plane_a = ATypePlane()
...
# when role click fire button
plane_a.fire() # when role click left button
plane_a.turn(left)
... plane_b = BTypePlane()
...

但是某一天老板突发奇想,我们的生意不好,是不是因为我们的飞机种类太少了,玩家觉得没意思,对,就是这样,那个产品经理你过来,我们需要多加几个飞机类型供玩家选择,你觉得如何?产品经理拍拍胸脯,向老板保证,没问题啊,我现在就加,于是乎,于是乎身为程序员的你就需要苦逼的,写出十几种飞机类型的代码,你觉得还可以承受,不就是拷贝粘贴么?
好了,现在你有了十几种飞机

class ATypePlane(Plane):
.... class BTypePlane(Plane):
... ... class MTypePlane(Plane):
...

可是有一天老板又突发奇想,为什么只能有速射弹和穿甲弹,为什么不多加几种,而且每过一关,都要升级子弹类型,而且还要在吃到升级奖励时能够马上升级子弹。产品经理拍手称快,大赞老板高明,并保证马上完成。这里程序员同学表示shit!可是大吼之后,还是要把活撸完啊,毕竟还要靠这微薄的薪水养家糊口。

拷贝粘贴大法虽好,但是此处似乎有些粗鲁,且也无法在运行时进行飞机行为的更改啊。更何况将来一旦又有更改,那么就需要所有的飞机类型都更改。我们总结一下我们面临的问题:

  • 如果将来的fire行为有更改,我们需要更改所有涉及到的飞机类型
  • 我们无法在运行时动态的更改某个飞机类型的fire行为
  • 另外如果我们将来想让某些飞机没有fire行为,目前的继承方式是无法做到的

这就是我们面临的问题,那么到底该如何是好呢?软件设计的一个原则就是把变化抽离出来,单独封装
那我们能不能把飞机的fire行为单独抽离出来呢?

答案是可以,这就是我们的策略模式了。

是什么?

简单来说,策略模式就是把变化的行为抽离出来,单独封装,使用的时候,直接调用这些封装好的行为即可。
以我们的游戏项目为例,我们可以把fire()行为拿出来

class FireAction(object):
def fire():
pass class SpeedFire(FireAction):
def fire():
... #定义速射子弹 class ArmorPiercerFire(FireAction):
def fire():
... #定义穿甲弹行为 #可以定义更多的fire行为
...

现在我们需要在我们的Plane当中加入fire行为

class Plane(object):
def __init__(self, fire_action=None):
self.color = black
self.life_left = 100
self.fire_action = fire_action def turn(direction):
"""用于实现飞机的转向"""
...

子类的实现如下:

class ATypePlane(Plane):
def __init__(self, fire_action=None):
if (fire_action is None or
(not isinstance(fire_action, FireAction))):
fire_action = ArmorPiercerFire() #默认使用ArmorPiercerFire super(ATypePlane, self).__init__(fire_action) def fire(fire_action=None):
if fire_action is not None and isinstance(fire_action, FireAction):
self.fire_action = fire_action
self.fire_action.fire() #没有fire行为的飞机
class CTypePlane(Plane):
def __init__(self):
super(CTypePlane, self).__init__()
...

使用子类的程序可能如下:

plane_a = ATypePlane()
plane_a.fire() #这时使用默认的ArmorPiercerFire #根据游戏的规则升级fire
plane_a.fire(SpeedFire()) #这时使用SpeedFire

现在我们来看下之前面临的问题是否解决了呢。

  • 如果将来的fire行为有更改,我们需要更改所有涉及到的飞机类型

目前来看如果将来的某个fire行为需要更改,我们只需要修改特定的FireAction子类即可,不需要再更改所有的子飞机类型

  • 我们无法在运行时动态的更改某个飞机类型的fire行为

我们可以根据需要在fire的时候动态的更改fire行为,只需要传递特定的FireAction类型即可

  • 另外如果我们将来想让某些飞机没有fire行为,目前的继承方式是无法做到的

我们的CTypePlane已经没有fire行为了

这样看来我们之前面临的三个问题都通过策略模式解决了。而且将来如果新增策略(即fire行为)时,也无需担心之前的代码,只需要重新实现一个FireAction子类即可,那么下面让我们总结下什么情况下使用策略模式吧。

怎么用?

通过我们之前的飞机游戏的例子我们可以看出当出现如下情况时有必要采用策略模式:

什么情况下使用

  • 当一个类型可能会有很多种子类,且这些子类的某些行为相同,某些行为不相同
  • 子类的行为需要在运行时更改

这时就有必要采用策略模式将不同的行为定义成不同的“策略”,同时通过组合的方式来使用这些“策略”,这也是设计原则之一,即能用组合就不要使用继承

什么情况下不用

学习设计模式最忌讳过度使用,所以如果当你确定不会有很多子类,也不需要动态更改行为时就不需要使用策略模式。这涉及另外一个设计原则,凡是不使用设计模式也能很好解决问题的时候就不要使用设计模式,这个是我说的。

好了,现在看官已经看懂了策略模式,如果看官觉得不错,就请点个赞鼓励下作者,好让我能鼓起精神写完这个系列。

作者:geekpy
链接:https://www.jianshu.com/p/e535d23dab0e
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

设计模式(Python)-策略模式的更多相关文章

  1. python设计模式之策略模式

    每次看到项目中存在大量的if else代码时,都会心生一丝不安全感. 特别是产品给的需求需要添加或者更改一种if条件时,生怕会因为自己的疏忽而使代码天崩地裂,哈哈,本文的目的就是来解决这种不安全感的, ...

  2. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  3. PHP设计模式之策略模式

    前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...

  4. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...

  5. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  6. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  7. 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查

    原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...

  8. [design-patterns]设计模式之一策略模式

    设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...

  9. 设计模式入门,策略模式,c++代码实现

    // test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...

随机推荐

  1. vue 基础笔记

    Vue01笔记 ES6模块使用和新的函数声明方式 a) Import 一定不能放在函数内, 建议放在上方 b) Export 除了声明式的以外, 尽量放在代码的下方 Import {name,age} ...

  2. ubuntu14.04 安装mono

    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831 ...

  3. Java学习笔记心得——初识Java

    初识Java 拿到这本厚厚的<Java学习笔记>,翻开目录:Java平台概论.从JDK到TDE.认识对象.封装.继承与多态...看着这些似懂非懂的术语名词,心里怀着些好奇与担忧,就这样我开 ...

  4. 20145221 《Java程序设计》第十周学习总结

    20145221 <Java程序设计>第十周学习总结 网络编程 网络概述 概述 网络编程技术是当前一种主流的编程技术,随着联网趋势的逐步增强以及网络应用程序的大量出现,所以在实际的开发中网 ...

  5. POJ 1860 Currency Exchange(Bellman-Ford)

    https://vjudge.net/problem/POJ-1860 题意: 有多种货币,可以交换,有汇率并且需要支付手续费,判断是否能通过不断交换使本金变多. 思路: Bellman-Ford算法 ...

  6. building '_mysql' extension error: [WinError 2] 系统找不到指定的文件。

    D:\4yanjiiu\APIzidong\MySQL-python-1.2.5>py running install running bdist_egg running egg_info wr ...

  7. ggplot2作图详解7(完):主题(theme)设置

    凡是和数据无关的图形设置内容理论上都可以归为主题类,但考虑到一些内容(如坐标轴)的特殊性,可以允许例外的情况.主题的设置相当繁琐,很容易就占用了 大量的作图时间,应尽量把这些东西简化,把注意力主要放在 ...

  8. 例子.ZC简单.JSP和session

    1.环境: Win7x64.E:\ZC_IDE\Eclipse\Windows\eclipse-jee-mars-R-win32__apk__20180122_1457\eclipse.exe.E:\ ...

  9. tp5集成淘宝,微信,网易,新浪等第三方登录

    tp5集成淘宝,微信,网易,新浪等第三方登录 一.总结 一句话总结: 接口 链接 实现的话就是这些平台给的一个接口(链接),你通过这些接口登录进去之后,它会给你返回用户名,头像之类的信息,我们的网站存 ...

  10. hdu4990矩阵快速幂

    就是优化一段代码,用矩阵快速幂(刚开始想到了转移矩阵以为是错的) 在搜题解时发现了一个神奇的网站:http://oeis.org/ 用来找数列规律 的神器.... 规律就是an=an-1+2*an-2 ...