详解Python设计模式编程中观察者模式与策略模式的运用


Posted in Python onMarch 02, 2016

观察者模式

观察者模式:又叫发布订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时,会通知所有观察者对象,是他们能自动更新自己。

代码结构

class Topic(object):
  """主题类。保存所有观察者实例的引用,每个主题都可以有很多观察者
  可以增加和删除观察者"""
  def __init__(self):
    self.obs = []

  def Attach(self, ob):
    self.obs.append(ob)

  def Detach(self, ob):
    self.obs.remove(ob)

  def Notify(self):
    for ob in self.obs:
      ob.Update()

class Observer(object):
  """抽象观察者类,收到主题的变更通知时,更新自己"""
  def Update(self):
    raise NotImplementedError()

class ConcreteTopic(object):
  """一个具体主题"""
  def __init__(self):
    self.state = None

  def ChangeState(self, newState):
    self.state = newState
    self.Notify()

class ConcreteObserver(object):
  """一个具体监听类"""
  def __init__(self, topic):
    self.topic = topic

  def Update(self):
    print self.topic.state

def client():
  topic = ConcreteTopic()
  topic.Attach(ConcreteObserver(topic))

  topic.ChangeState('New State')

众多MQ中间件都是采用这种模式的思想来实现的。

观察者模式可以让主题和观察者之间解耦,互相之间尽可能少的依赖。不过抽象主题和抽象观察者之间还是有耦合的。

策略模式
策略模式: 定义了算法家族,分别封装起来,让他们之间可以互相替换。此模式让算法的变化不影响使用算法的客户。

代码框架

class Strategy(object):
  """抽象算法类"""
  def AlgorithmInterface(self):
    raise NotImplementedError()

class ConcreteStrategyA(Strategy):
  def AlgorithmInterface(self):
    print '算法A'

class ConcreteStrategyB(Strategy):
  def AlgorithmInterface(self):
    print '算法B'

class Context(object):
  """上下文,作用就是封装策略的实现细节,用户只需要知道有哪些策略可用"""
  def __init__(self, strategy):
    # 初始化时传入具体的策略实例
    self.strategy = strategy

  def ContextInterface(self):
    # 负责调用具体的策略实例的接口
    self.strategy.AlgorithmInterface()

def client(cond):
  # 策略模式的使用演示
  # 用户只需要根据不同的条件,将具体的算法实现类传递给Context,
  # 然后调用Context暴露给用户的接口就行了。
  if cond == 'A':
    context = Context(ConcreteStrategyA())
  elif cond == 'B':
    context = Context(ConcreteStrategyB())

  result = context.ContextInterface()

策略模式解决那类问题

在回答这个问题之前,先说下对策略模式的使用方式的感觉。上面的client函数,怎么看起来就像是简单工厂模式中的工厂函数呢?确实如此,实际上策略模式可以和简工厂模式结合起来,将更多细节封装在策略模式内部,让使用者更容易的使用。

那么策略模式和简单工厂模式有什么不同呢?策略模式中的算法是用来解决同一个问题的,根据时间、条件不同,算法的具体细节有差异,但最终解决的是同一个问题。在需求分析过程中,当听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式来处理这种变化的可能性。

缺点

使用者需要知道每一种策略的具体含义,并负责选择策略
改进

结合简单工厂模式,将策略选择封装在Context内部,解放client:

class Context(object):
  def __init__(self, cond):
    if cond == 'A':
      self.strategy = Context(ConcreteStrategyA())
    elif cond == 'B':
      self.strategy = Context(ConcreteStrategyB())

  def ContextInterface(self):
    self.strategy.AlgorithmInterface()


def client(cond):
  context = Context(cond)
  result = context.ContextInterface()

改进后的遗留问题

每次需要增加新的策略时,就需要修改Context的构造函数,增加一个新的判断分支。

Python 相关文章推荐
如何解决django配置settings时遇到Could not import settings 'conf.local'
Nov 18 Python
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
Dec 27 Python
pandas使用apply多列生成一列数据的实例
Nov 28 Python
Python图像处理实现两幅图像合成一幅图像的方法【测试可用】
Jan 04 Python
python对象与json相互转换的方法
May 07 Python
如何通过python的fabric包完成代码上传部署
Jul 29 Python
Python with标签使用方法解析
Jan 17 Python
Python使用type动态创建类操作示例
Feb 29 Python
Python调用接口合并Excel表代码实例
Mar 31 Python
Python实现常见的几种加密算法(MD5,SHA-1,HMAC,DES/AES,RSA和ECC)
May 09 Python
Python闭包及装饰器运行原理解析
Jun 17 Python
pandas 操作 Excel操作总结
Mar 31 Python
Python设计模式编程中解释器模式的简单程序示例分享
Mar 02 #Python
分析Python中设计模式之Decorator装饰器模式的要点
Mar 02 #Python
实例解析Python设计模式编程之桥接模式的运用
Mar 02 #Python
Python随机生成带特殊字符的密码
Mar 02 #Python
Python设计模式编程中Adapter适配器模式的使用实例
Mar 02 #Python
Python打造出适合自己的定制化Eclipse IDE
Mar 02 #Python
设计模式中的原型模式在Python程序中的应用示例
Mar 02 #Python
You might like
php数组使用规则分析
2015/02/27 PHP
Linux平台php命令行程序处理管道数据的方法
2016/11/10 PHP
关于PHP定时发送服务的解决办法
2017/04/23 PHP
php实现的统计字数函数定义与使用示例
2017/07/26 PHP
利用PHP获取汉字首字母并且分组排序详解
2017/10/22 PHP
Struts2的s:radio标签使用及用jquery添加change事件
2013/04/08 Javascript
JS中getYear()和getFullYear()区别分析
2014/07/04 Javascript
javascript实现获取字符串hash值
2015/05/10 Javascript
jquery实现带渐变淡入淡出并向右依次展开的多级菜单效果实例
2015/08/22 Javascript
谈一谈jQuery核心架构设计
2016/03/28 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
JavaScript获取键盘按键的键码(参照表)
2017/01/10 Javascript
JavaScript 函数的定义-调用、注意事项
2017/04/16 Javascript
全面解析jQuery中的$(window)与$(document)的用法区别
2017/08/15 jQuery
js判断输入框不能为空格或null值的实现方法
2018/03/02 Javascript
解析Json字符串的三种方法日常常用
2018/05/02 Javascript
JS实现百度网盘任意文件强制下载功能
2018/08/31 Javascript
一些你可能不熟悉的JS知识点总结
2019/03/15 Javascript
js实现类似iphone的网页滑屏解锁功能示例【附源码下载】
2019/06/10 Javascript
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
JS实现水平移动与垂直移动动画
2019/12/19 Javascript
原生js实现碰撞检测
2020/03/12 Javascript
[41:11]完美世界DOTA2联赛PWL S2 Inki vs Magma 第一场 11.22
2020/11/24 DOTA
使用Python设置tmpfs来加速项目的教程
2015/04/17 Python
Python字符串格式化
2015/06/15 Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
2016/11/19 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
Python处理session的方法整理
2019/08/29 Python
python定间隔取点(np.linspace)的实现
2019/11/27 Python
python手写均值滤波
2020/02/19 Python
Windows 下python3.8环境安装教程图文详解
2020/03/11 Python
用python写PDF转换器的实现
2020/10/29 Python
酒店总经理欢迎词
2014/01/15 职场文书
青年文明号事迹材料
2014/01/18 职场文书
2015年度个人思想工作总结
2015/04/08 职场文书
Vue3中的Refs和Ref详情
2021/11/11 Vue.js