详解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使用PyV8执行javascript代码示例分享
Dec 04 Python
python处理二进制数据的方法
Jun 03 Python
深入解析Python的Tornado框架中内置的模板引擎
Jul 11 Python
简单谈谈python中的多进程
Nov 06 Python
Python利用itchat对微信中好友数据实现简单分析的方法
Nov 21 Python
win8下python3.4安装和环境配置图文教程
Jul 31 Python
用Q-learning算法实现自动走迷宫机器人的方法示例
Jun 03 Python
pytz格式化北京时间多出6分钟问题的解决方法
Jun 21 Python
Python调用Windows API函数编写录音机和音乐播放器功能
Jan 05 Python
tensorflow 实现打印pb模型的所有节点
Jan 23 Python
通过python检测字符串的字母
Feb 18 Python
Django项目如何正确配置日志(logging)
Apr 29 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
Oracle Faq(Oracle的版本)
2006/10/09 PHP
加强版phplib的DB类
2008/03/31 PHP
PHP程序61条面向对象分析设计的经验小结
2008/11/12 PHP
有关JSON以及JSON在PHP中的应用
2010/04/09 PHP
PHP自动生成表单代码分享
2015/06/19 PHP
解决Laravel5.5下的toArray问题
2019/10/15 PHP
Jquery Ajax学习实例3 向WebService发出请求,调用方法返回数据
2010/03/16 Javascript
在JavaScript中使用timer示例
2014/05/08 Javascript
jquery+javascript编写国籍控件
2015/02/12 Javascript
js表格排序实例分析(支持int,float,date,string四种数据类型)
2015/05/06 Javascript
javascript背景时钟实现方法
2015/06/18 Javascript
使用Promise解决多层异步调用的简单学习心得
2016/05/17 Javascript
基于JS实现导航条flash导航条
2016/06/17 Javascript
深入理解JavaScript中的并行处理
2016/09/22 Javascript
BootStrap fileinput.js文件上传组件实例代码
2017/02/20 Javascript
nodejs开发——express路由与中间件
2017/03/24 NodeJs
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
2017/07/27 Javascript
vue cli 3.0 使用全过程解析
2018/06/14 Javascript
vue-cli随机生成port源码的方法
2019/09/02 Javascript
Vue解析剪切板图片并实现发送功能
2020/02/04 Javascript
ES5 模拟 ES6 的 Symbol 实现私有成员功能示例
2020/05/06 Javascript
vue项目中播放rtmp视频文件流的方法
2020/09/17 Javascript
js canvas实现五子棋小游戏
2021/01/22 Javascript
Python中super关键字用法实例分析
2015/05/28 Python
python的else子句使用指南
2016/02/27 Python
python3 tkinter实现点击一个按钮跳出另一个窗口的方法
2019/06/13 Python
python保存log日志,实现用log日志画图
2019/12/24 Python
python 使用事件对象asyncio.Event来同步协程的操作
2020/05/04 Python
Python爬取12306车次信息代码详解
2020/08/12 Python
Python实现文件压缩和解压的示例代码
2020/08/12 Python
使用python对excel表格处理的一些小功能
2021/01/25 Python
CSS3系列教程:背景图片(背景大小和多背景图) 应用说明
2012/12/19 HTML / CSS
利用css3径向渐变做一张优惠券的示例
2018/03/22 HTML / CSS
新西兰航空中国官网:Air New Zealand China
2018/07/24 全球购物
美国现代家具购物网站:LexMod
2019/01/09 全球购物
win sever 2022如何占用操作主机角色
2022/06/25 Servers