详解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 相关文章推荐
详细介绍Python语言中的按位运算符
Nov 26 Python
使用cx_freeze把python打包exe示例
Jan 24 Python
详解Python中的条件判断语句
May 14 Python
Python二分查找详解
Sep 13 Python
Python的Twisted框架上手前所必须了解的异步编程思想
May 25 Python
opencv python 2D直方图的示例代码
Jul 20 Python
python 实现倒排索引的方法
Dec 25 Python
Python 异步协程函数原理及实例详解
Nov 13 Python
python程序输出无内容的解决方式
Apr 09 Python
计算Python Numpy向量之间的欧氏距离实例
May 22 Python
PyQT5 实现快捷键复制表格数据的方法示例
Jun 19 Python
Ubuntu16安装Python3.9的实现步骤
Dec 15 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下获取客户端ip地址的函数
2010/03/15 PHP
php设计模式 Observer(观察者模式)
2011/06/26 PHP
PHP中session跨子域的三种实现方法
2016/07/25 PHP
PHP中类型转换 ,常量,系统常量,魔术常量的详解
2017/10/26 PHP
为Yahoo! UI Extensions Grid增加内置的可编辑器
2007/03/10 Javascript
零基础学JavaScript最新动画教程+iso光盘下载
2008/01/22 Javascript
IE bug table元素的innerHTML
2010/01/11 Javascript
jQuery最佳实践完整篇
2011/08/20 Javascript
js substr支持中文截取函数代码(中文是双字节)
2013/04/17 Javascript
22点关于jquery性能优化的建议
2014/05/28 Javascript
使用jQuery实现input数值增量和减量的方法
2015/01/24 Javascript
jQuery仿Flash上下翻动的中英文导航菜单实例
2015/03/10 Javascript
js 模仿锚点定位的实现方法
2016/11/19 Javascript
js数组操作方法总结(必看篇)
2016/11/22 Javascript
jquery 实现复选框的全选操作实例代码
2017/01/24 Javascript
ES6使用let命令更简单的实现块级作用域实例分析
2017/03/31 Javascript
详解微信小程序input标签正则初体验
2018/08/18 Javascript
Vue实现兄弟组件间的联动效果
2020/01/21 Javascript
[04:11]DOTA2上海特级锦标赛主赛事首日TOP10
2016/03/03 DOTA
精确查找PHP WEBSHELL木马的方法(1)
2011/04/12 Python
教你如何在Django 1.6中正确使用 Signal
2014/06/22 Python
如何搜索查找并解决Django相关的问题
2014/06/30 Python
Python的Django框架中的表单处理示例
2015/07/17 Python
python如何派生内置不可变类型并修改实例化行为
2018/03/21 Python
用Q-learning算法实现自动走迷宫机器人的方法示例
2019/06/03 Python
详解Django 时间与时区设置问题
2019/07/23 Python
正则给header的冒号两边参数添加单引号(Python请求用)
2019/08/09 Python
Vision Directa智利眼镜网:框架眼镜、隐形眼镜和名牌太阳眼镜
2016/11/23 全球购物
科颜氏美国官网:Kiehl’s美国
2017/01/31 全球购物
企业项目策划书
2014/01/11 职场文书
高中学生期末评语
2014/04/25 职场文书
2015年物业公司保洁工作总结
2015/10/22 职场文书
springboot中一些比较常用的注解总结
2021/06/11 Java/Android
Python中使用ipython的详细教程
2021/06/22 Python
OpenCV实现反阈值二值化
2021/11/17 Java/Android
golang三种设计模式之简单工厂、方法工厂和抽象工厂
2022/04/10 Golang