详解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 struct模块解析
Jun 12 Python
Python异常处理总结
Aug 15 Python
Python中map和列表推导效率比较实例分析
Jun 17 Python
在Python中通过threading模块定义和调用线程的方法
Jul 12 Python
Python利用QQ邮箱发送邮件的实现方法(分享)
Jun 09 Python
Python3实现的简单验证码识别功能示例
May 02 Python
Pycharm以root权限运行脚本的方法
Jan 19 Python
详解python selenium 爬取网易云音乐歌单名
Mar 28 Python
详解mac python+selenium+Chrome 简单案例
Nov 08 Python
Pandas-Cookbook 时间戳处理方式
Dec 07 Python
python实现录制全屏和选择区域录屏功能
Feb 05 Python
scrapy-splash简单使用详解
Feb 21 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
在字符串中把网址改成超级链接
2006/10/09 PHP
PHP 实现的将图片转换为TXT
2015/10/21 PHP
js Select下拉列表框进行多选、移除、交换内容的具体实现方法
2013/08/13 Javascript
JS控制一个DIV层在指定时间内消失的方法
2014/02/17 Javascript
AngularJS实现全选反选功能
2015/12/08 Javascript
JS动态插入并立即执行回调函数的方法
2016/04/21 Javascript
动态加载JavaScript文件的两种方法
2016/04/22 Javascript
canvas学习之API整理笔记(一)
2016/12/29 Javascript
微信小程序微信支付接入开发实例详解
2017/04/12 Javascript
vue.js,ajax渲染页面的实例
2018/02/11 Javascript
在Vue环境下利用worker运行interval计时器的步骤
2019/08/01 Javascript
如何使用 JavaScript 操作浏览器历史记录 API
2020/11/24 Javascript
python实现的udp协议Server和Client代码实例
2014/06/04 Python
Python列表推导式、字典推导式与集合推导式用法实例分析
2018/02/07 Python
理想高通滤波实现Python opencv示例
2019/01/30 Python
Python中numpy模块常见用法demo实例小结
2019/03/16 Python
解析python实现Lasso回归
2019/09/11 Python
python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作
2019/12/11 Python
CSS3 渐变(Gradients)之CSS3 径向渐变
2016/07/08 HTML / CSS
荷兰鞋子在线:Nelson Schoenen
2017/12/25 全球购物
英国复古皮包品牌:Beara Beara
2018/07/18 全球购物
纽约海:Sea New York
2018/11/04 全球购物
如何打印出当前源文件的文件名以及源文件的当前行号
2015/04/05 面试题
测量实习生自我鉴定
2013/09/19 职场文书
思想品德自我评价
2014/02/04 职场文书
铲车司机岗位职责
2014/03/15 职场文书
中学生操行评语
2014/04/24 职场文书
2014年全国法制宣传日宣传活动方案
2014/11/02 职场文书
2014年行政工作总结
2014/11/19 职场文书
自主招生自荐信怎么写
2015/03/24 职场文书
商务信函英语问候语
2015/11/10 职场文书
Nginx已编译的nginx-添加新模块
2021/04/01 Servers
python实现批量移动文件
2021/04/05 Python
探究Mysql模糊查询是否区分大小写
2021/06/11 MySQL
Python初识逻辑与if语句及用法大全
2021/08/07 Python
python中使用redis用法详解
2022/12/24 Redis