详解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 相关文章推荐
wxpython 学习笔记 第一天
Mar 16 Python
Python基于贪心算法解决背包问题示例
Nov 27 Python
python实现Decorator模式实例代码
Feb 09 Python
基于anaconda下强大的conda命令介绍
Jun 11 Python
如何优雅地改进Django中的模板碎片缓存详解
Jul 04 Python
通过python的matplotlib包将Tensorflow数据进行可视化的方法
Jan 09 Python
详解pandas.DataFrame中删除包涵特定字符串所在的行
Apr 04 Python
Python3环境安装Scrapy爬虫框架过程及常见错误
Jul 12 Python
Python hashlib模块加密过程解析
Nov 05 Python
关于Python3 lambda函数的深入浅出
Nov 27 Python
Python猜数字算法题详解
Mar 01 Python
Python3爬虫中Ajax的用法
Jul 10 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中常用编辑器推荐
2007/01/02 PHP
PHP CLI模式下的多进程应用分析
2013/06/03 PHP
PHP使用fopen与file_get_contents读取文件实例分享
2016/03/04 PHP
php微信开发之上传临时素材
2016/06/24 PHP
获取Javscript执行函数名称的方法
2006/12/22 Javascript
jQuery 跨域访问问题解决方法
2009/12/02 Javascript
javascript复制对象使用说明
2011/06/28 Javascript
javascript 在firebug调试时用console.log的方法
2012/05/10 Javascript
只需20行代码就可以写出CSS覆盖率测试脚本
2013/04/24 Javascript
解析Javascript小括号“()”的多义性
2013/12/03 Javascript
js实现网页随机切换背景图片的方法
2014/11/01 Javascript
使用javascript将时间转换成今天,昨天,前天等格式
2015/06/25 Javascript
浅谈JavaScript中setInterval和setTimeout的使用问题
2015/08/01 Javascript
JS实现仿苹果底部任务栏菜单效果代码
2015/08/28 Javascript
js实现跨域的多种方法
2015/12/25 Javascript
bootstrap table分页模板和获取表中的ID方法
2017/01/10 Javascript
js 获取今天以及过去日期
2017/04/11 Javascript
jQuery实现右侧抽屉式在线客服功能
2017/12/25 jQuery
vue项目如何刷新当前页面的方法
2018/05/18 Javascript
Vue核心概念Action的总结
2019/01/18 Javascript
解决layui动态加载复选框无法选中的问题
2019/09/20 Javascript
Vue.js的模板语法详解
2020/02/16 Javascript
微信小程序实现比较功能的方法汇总(五种方法)
2020/03/07 Javascript
vue实现移动端H5数字键盘组件使用详解
2020/08/25 Javascript
Python : turtle色彩控制实例详解
2020/01/19 Python
python读取多层嵌套文件夹中的文件实例
2020/02/27 Python
Python 判断时间是否在时间区间内的实例
2020/05/16 Python
Python-for循环的内部机制
2020/06/12 Python
长安大学毕业生自我鉴定
2014/01/17 职场文书
优秀班组长事迹
2014/05/31 职场文书
优秀毕业生求职信
2014/06/05 职场文书
化学教育专业自荐信
2014/07/04 职场文书
回门宴新娘答谢词
2015/09/29 职场文书
《蚂蚁和蝈蝈》教学反思
2016/02/22 职场文书
正确的理解和使用Django信号(Signals)
2021/04/14 Python
Python爬虫入门案例之爬取去哪儿旅游景点攻略以及可视化分析
2021/10/16 Python