举例讲解Python设计模式编程中的访问者与观察者模式


Posted in Python onJanuary 26, 2016

访问者模式
我觉得Visitor模式是在补修改已有程序结构前提下,通过添加额外的访问者完成对代码功能的拓展 为什么这样用?当你的类层次较多,在某层结构中增加新的方法,要是在基类上面添加或者变更,可能破坏原来的设计, 有兼容问题,所以只在需要的类上面动态添加。

python的例子
这里是个构建车的例子,每个部件都有一个accept的方法接受我上面说的所谓'访问者',而这个访问者 以参数的方式传进来,但是其实他是一个含有一些功能的类的实例,它拥有很多个visit开头的方法对应不同的部件。 这样就不需要修改这些部件,而只是修改我们的访问者类的相关部分。

# 轮子,引擎, 车身这些定义好了都不需要变动
class Wheel:
  def __init__(self, name):
    self.name = name
  def accept(self, visitor):
    # 每个visitor是同样的,但是其中的方法是不一样的,比如这里是visitWheel,
    # 然后传入了self,想想?他其实想做什么就能做什么
    visitor.visitWheel(self)

class Engine:
  def accept(self, visitor):
    visitor.visitEngine(self)

class Body:
  def accept(self, visitor):
    visitor.visitBody(self)

# 我们要组合成车
class Car:
  def __init__(self):
    self.engine = Engine()
    self.body  = Body()
    self.wheels = [ Wheel("front left"), Wheel("front right"),
            Wheel("back left") , Wheel("back right") ]

  # 这个也不需要在动,他只是上面部件的组合,只是做了属性的委托
  def accept(self,visitor):
    visitor.visitCar(self)
    self.engine.accept(visitor)
    self.body.accept(visitor)
    for wheel in self.wheels:
      wheel.accept(visitor)

# 这个才是我们的访问者,每次的修改都在这里面
class PrintVisitor:
  def visitWheel(self, wheel):
    print "Visiting "+wheel.name+" wheel"
  def visitEngine(self, engine):
    print "Visiting engine"
  def visitBody(self, body):
    print "Visiting body"
  def visitCar(self, car):
    print "Visiting car"

if __name__ == '__main__':
  car = Car()
  visitor = PrintVisitor()
  car.accept(visitor)

观察者模式
当我们希望一个对象的状态发生变化,那么依赖与它的所有对象都能相应变化(获得通知),那么就可以用到Observer模式, 其中的这些依赖对象就是观察者的对象,那个要发生变化的对象就是所谓'观察者'

python的例子

# 这个是观察者基类
class Subject(object):
  def __init__(self):
    self._observers = []

  # 添加依赖的对象
  def attach(self, observer):
    if not observer in self._observers:
      self._observers.append(observer)

  # 取消添加
  def detach(self, observer):
    try:
      self._observers.remove(observer)
    except ValueError:
      pass

  # 这里只是通知上面注册的依赖对象新的变化
  def notify(self, modifier=None):
    for observer in self._observers:
      # 可以设置过滤条件,对不符合过滤条件的更新
      if modifier != observer:
        observer.update(self)


# 观察者类
class Data(Subject):
  def __init__(self, name=''):
    super(Data, self).__init__()
    self.name = name
    self._data = 0

  # python2.6新增的写法,获取属性为property,设置属性为(假设属性名字为x)@x.setter,删除为@x.deleter
  @property
  def data(self):
    return self._data

  @data.setter
  def data(self, value):
    self._data = value
    self.notify()

# 这里有2个被观察者,也就是依赖的对象,每次Data有改变,这2个view都会变动
class HexViewer(object):
  def update(self, subject):
    print 'HexViewer: Subject %s has data 0x%x' % (subject.name, subject.data)

class DecimalViewer(object):
  def update(self, subject):
    print 'DecimalViewer: Subject %s has data %d' % (subject.name, subject.data)


if __name__ == '__main__':

  data1 = Data('Data 1')
  data2 = Data('Data 2')
  view1 = DecimalViewer()
  view2 = HexViewer()
  data1.attach(view1)
  data1.attach(view2)
  data2.attach(view2)
  data2.attach(view1)

  print "Setting Data 1 = 10"
  data1.data = 10
  print "Setting Data 2 = 15"
  data2.data = 15
  print "Setting Data 1 = 3"
  data1.data = 3
  print "Setting Data 2 = 5"
  data2.data = 5
  print "Update data1's view2 Because view1 is be filtered"
  data1.notify(modifier=view1) 
  print "Detach HexViewer from data1 and data2."
  data1.detach(view2)
  data2.detach(view2)
  print "Setting Data 1 = 10"
  data1.data = 10
  print "Setting Data 2 = 15"
  data2.data = 15
Python 相关文章推荐
pymongo为mongodb数据库添加索引的方法
May 11 Python
Python OpenCV之图片缩放的实现(cv2.resize)
Jun 28 Python
Python Numpy计算各类距离的方法
Jul 05 Python
解决yum对python依赖版本问题
Jul 05 Python
基于Python的ModbusTCP客户端实现详解
Jul 13 Python
Python安装selenium包详细过程
Jul 23 Python
python os.path.isfile 的使用误区详解
Nov 29 Python
浅谈Keras中shuffle和validation_split的顺序
Jun 19 Python
面向新手解析python Beautiful Soup基本用法
Jul 11 Python
python3 中时间戳、时间、日期的转换和加减操作
Jul 14 Python
python如何快速拼接字符串
Oct 28 Python
Python爬虫回测股票的实例讲解
Jan 22 Python
Python函数中*args和**kwargs来传递变长参数的用法
Jan 26 #Python
python中的编码知识整理汇总
Jan 26 #Python
在MAC上搭建python数据分析开发环境
Jan 26 #Python
python黑魔法之编码转换
Jan 25 #Python
Python编程中对文件和存储器的读写示例
Jan 25 #Python
Python开发如何在ubuntu 15.10 上配置vim
Jan 25 #Python
详解Python验证码识别
Jan 25 #Python
You might like
PHP产生随机字符串函数
2006/12/06 PHP
php 启动报错如何解决
2014/01/17 PHP
php中注册器模式类用法实例分析
2015/11/03 PHP
CI框架使用composer安装的依赖包步骤与方法分析
2016/11/21 PHP
PHP实现文字写入图片功能
2019/02/18 PHP
利用google提供的API(JavaScript接口)获取网站访问者IP地理位置的代码详解
2010/07/24 Javascript
浅析Js中的单引号与双引号问题
2013/11/06 Javascript
js与jquery获取父元素,删除子元素的两种不同方法
2014/01/09 Javascript
jquery获取tagName再进行判断
2014/05/29 Javascript
JS、CSS以及img对DOMContentLoaded事件的影响
2014/08/12 Javascript
JavaScript实现的类字典插入或更新方法实例
2015/07/10 Javascript
web前端开发JQuery常用实例代码片段(50个)
2015/08/28 Javascript
全面解析Bootstrap表单使用方法(表单按钮)
2015/11/24 Javascript
浅谈JavaScript 浏览器对象
2016/06/03 Javascript
jQuery代码实现实时获取时间
2017/01/29 Javascript
nodeJS实现简单网页爬虫功能的实例(分享)
2017/06/08 NodeJs
React数据传递之组件内部通信的方法
2017/12/31 Javascript
vue 页面加载进度条组件实例
2018/02/05 Javascript
原生JS实现旋转轮播图+文字内容切换效果【附源码】
2018/09/29 Javascript
vue-cli 脚手架基于Nightwatch的端到端测试环境的过程
2018/09/30 Javascript
Webpack4+Babel7+ES6兼容IE8的实现
2019/04/10 Javascript
如何让Nodejs支持H5 History模式(connect-history-api-fallback源码分析)
2019/05/30 NodeJs
vue下axios拦截器token刷新机制的实例代码
2020/01/17 Javascript
JS实现进度条动态加载特效
2020/03/25 Javascript
使用Python发送邮件附件以定时备份MySQL的教程
2015/04/25 Python
使用python实现省市三级菜单效果
2016/01/20 Python
Python多线程应用于自动化测试操作示例
2018/12/06 Python
详解用Python练习画个美队盾牌
2019/03/23 Python
Python文件操作方法详解
2020/02/09 Python
Python正则表达式如何匹配中文
2020/05/27 Python
Pyinstaller打包Scrapy项目的实现步骤
2020/09/22 Python
迪斯尼商品官方网站:ShopDisney
2016/08/01 全球购物
带薪年假请假条
2014/02/04 职场文书
民主评议党员工作总结
2014/10/20 职场文书
自主招生自荐信怎么写
2015/03/24 职场文书
美容院员工规章制度
2015/08/05 职场文书