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

  GOF对策略模式的解释是: 定义一系列算法, 把它们一个个封装起来,并且使它们可相互替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展, 子类化)。

  策略模式结构图如下:

  生活中商场搞活动给消费者派送了一批优惠券,优惠券分三种, 一种是满减券满100减10元, 一种是打折券满200打8折, 一种折扣券是满300打7.5折然后送鸡蛋一打(价值15),如果我们是商场后台程序员,我们要计算每个客户最后实际支付了多少钱,那这个程序你会怎样去设计?

01、 没有使用设计模式的版本

class Order:
def __init__(self, money, coupon):
self.money = money
self.coupon = coupon def total_money(self):
if self.coupon == 1 and self.money >= 100:
return self.money - 10
elif self.coupon == 2 and self.money >= 200:
return self.money * 0.8
elif self.coupon == 3 and self.money >= 300:
return self.money * 0.75 -15
return self.money if __name__ == '__main__': order1 = Order(102, 1)
order2 = Order(250, 2)
order3 = Order(372, 3)
order4 = Order(190, 2)
o1 = order1.total_money()
o2 = order2.total_money()
o3 = order3.total_money()
o4 = order4.total_money()
print(o1, o2, o3, o4)

  在平常的开发过程中,我们及其容易设计出这样的代码,夹杂着大量的if else语句,程序耦合性很高,一旦发生修改不小心就天崩地裂了, 严重违反我们八大设计原则的开闭原则。

  接下来我们用策略设计模式来设计我们的程序。

02、首先设计策略基类

from abc import ABC, abstractmethod

class BaseStrategy(ABC):

    @abstractmethod
def calculate(cls, money):
pass

  策略基类继承ABC类(抽象类)在方法上加上abstractmethod表示子类必须重写这个方法,不然会报错。

03、设计策略子类

class FullOneHundredStrategy(BaseStrategy):

    @classmethod
def calculate(cls, money):
if money >= 100:
return money - 10
return money class FullTwoHundredStrategy(BaseStrategy): @classmethod
def calculate(cls, money):
if money >= 200:
return money * 0.8
return money class FullThreeHundredStrategy(BaseStrategy): @classmethod
def calculate(cls, money):
if money >= 300:
return money * 0.75 - 15
return money

  分别设计三个策略子类并重写对应的计算方法,如果以后新增新的优惠券就可以增加一个新的子类即可。

04、设计订单类

class Order:

    coupon_map = {
1: FullOneHundredStrategy,
2: FullTwoHundredStrategy,
3: FullThreeHundredStrategy
} def __init__(self, money, coupon):
self.money = money
self.coupon = coupon def total_money(self):
return self.coupon_map.get(self.coupon).calculate(self.money)

  订单类包括实例属性money,和优惠券的种类, 并有一个类属性map,在实际开发中这个Map一般会放到公共文件中。

05、上下文中计算总金额

if __name__ == '__main__':

    order1 = Order(102, 1)
order2 = Order(250, 2)
order3 = Order(372, 3)
order4 = Order(190, 2)
o1 = order1.total_money()
o2 = order2.total_money()
o3 = order3.total_money()
o4 = order4.total_money()
print(o1, o2, o3, o4)

我们打印结果:

  和我们期望的结果一样,这样就完美的消除了大量的if else语句了, 更重要的是这样使策略与订单类解耦了,增加了程序的可复用性,和维护性。

06、总结

策略设计模式的好处:

  1. Strategy及其子类为组件提供了一系列可重用的算法, 从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
  2. Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常需要Strategy模式。

策略模式的劣处:

  1. 当策略越来愈多,就需要写更多的策略子类,后期接手的人可能就会有点懵了。
  2. 消除的if else判断语句仅适用于前后判断之间没有强关联性的情况, 如果判断有强关联可能需要用到另一个设计模式责任链设计模式。

ps:前后判断强关联如上述举例改成:商场活动不需要优惠券,只要你消费满100就减10,满200打8折,这样前后判断就有比较强的关联性了,此时的策略模式就不能有效消除if else判断语句了。

在最后我们依然需要加上我们设计模式的八大原则:

  1. 依赖倒置原则(DIP)
  • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
  • 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。
  1. 开放封闭原则(OCP)
  • 对扩展开放,对更改封闭。
  • 类模块应该是可扩展的,但是不可修改。
  1. 单一职责原则(SRP)
  • 一个类应该仅有一个引起它变化的原因。
  • 变化的方向隐含着类的责任。
  1. Liskov 替换原则(LSP)
  • 子类必须能够替换它们的基类(IS-A)。
  • 继承表达类型抽象。
  1. 接口隔离原则(ISP)
  • 不应该强迫客户程序依赖它们不用的方法。
  • 接口应该小而完备。
  1. 优先使用对象组合,而不是类继承
  • 类继承通常为“白箱复用”,对象组合通常为“黑箱复用” 。
  • 继承在某种程度上破坏了封装性,子类父类耦合度高。
  • 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
  1. 封装变化点
  • 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
  1. 针对接口编程,而不是针对实现编程
  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
  • 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案

python设计模式之策略模式的更多相关文章

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

    这几天太忙了,都没空写,所以持续了好几天. 1.策略模式的定义: 策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 通俗的讲,也就是将那些使用的方法 ...

  2. Python设计模式(2)-策略模式

    # 策略模式和简单工厂模式相比,少了使用switch case 做判断,然后去实例化相应的 # 对象,比简单工厂模式更灵活. 它们代码的区别就在于此处使用了抽象类代替工厂类 # coding=utf- ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. pip安装Python库速度慢的解决方法

    最近在写大数据文本挖掘的考查报告,需要用到 jieba切词,于是在pycharm中安装 jieba 库 首先是在 File—settings中通过搜索安装,然而安了五分钟之后还是失败了 于是通过终端输 ...

  2. Java 解析 XML文件

    ​个人博客网:https://wushaopei.github.io/    (你想要这里多有) package com.example.poiutis.xml; import com.example ...

  3. Java实现 LeetCode 44 通配符匹配

    44. 通配符匹配 给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个字 ...

  4. java实现第三届蓝桥杯DNA对比

    DNA对比 脱氧核糖核酸即常说的DNA,是一类带有遗传信息的生物大分子.它由4种主要的脱氧核苷酸(dAMP.dGMP.dCMT和dTMP)通过磷酸二酯键连接而成.这4种核苷酸可以分别记为:A.G.C. ...

  5. PAT 旧键盘打字

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 行中分别给出坏掉的那些键.以及应该输入 ...

  6. mysql基础之-mysql锁和事务(七)

    0x01 MySQL锁: 执行操作时施加锁的模式 读锁:用户在读的时候施加的锁,为防止别人修改,但是用户可以读,还被称为共享锁 不会对其他用户进行阻塞 理解: ----->(这里的不阻塞,是可以 ...

  7. 如何解决ubuntu 12.04重启后出现waiting for network configuration和网络标志消失问题

    如何解决ubuntu 12.04重启后出现waiting for network configuration和网络标志消失问题 作为菜鸟的我在学着设置网络后,重启电脑后显示 waiting forne ...

  8. Linux网卡驱动移植--Dm9000网卡驱动分析

    1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...

  9. 2020阿里最新出品的泰山版Java开发手册,告别垃圾代码

    说起华山,我就想起岳不群,不,令狐冲:说起泰山,我就想起司马迁,他的那句名言"人总有一死,或重于泰山,或轻于鸿毛",真的发人深省啊.这就意味着,阿里出品的泰山版 Java 开发手册 ...

  10. 如何在Vim中的查找替换

    “%s/最/第二/g” 用vim的人都知道,这是把所有“最”替换成“第二”的意思.其实vim的查找替换功能非常强大,用的好可以极大提升效率. vim的查找替换命令如下所示:    :{作用范围}s/{ ...