举例讲解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 相关文章推荐
python实现ping的方法
Jul 06 Python
在Django的视图中使用数据库查询的方法
Jul 16 Python
python运行时间的几种方法
Jun 17 Python
Python查找第n个子串的技巧分享
Jun 27 Python
python中提高pip install速度
Feb 14 Python
解决Jupyter因卸载重装导致的问题修复
Apr 10 Python
Pytorch通过保存为ONNX模型转TensorRT5的实现
May 25 Python
python删除某个目录文件夹的方法
May 26 Python
利用Vscode进行Python开发环境配置的步骤
Jun 22 Python
基于opencv实现简单画板功能
Aug 02 Python
Python中的面向接口编程示例详解
Jan 17 Python
Python游戏开发实例之graphics实现AI五子棋
Nov 01 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中explode函数和split函数的区别小结
2016/08/24 PHP
用js生产批量批处理执行命令
2008/07/28 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
纯JAVASCRIPT图表动画插件Highcharts Examples
2011/04/16 Javascript
基于datagrid框架的查询
2013/04/08 Javascript
js中 关于undefined和null的区别介绍
2013/04/16 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
2013/05/17 Javascript
JS获取地址栏参数的两种方法(简单实用)
2016/06/14 Javascript
第四篇Bootstrap网格系统偏移列和嵌套列
2016/06/21 Javascript
解决vue中监听input只能输入数字及英文或者其他情况的问题
2018/08/30 Javascript
深入理解JavaScript 箭头函数
2019/05/30 Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
2019/06/19 jQuery
基于javascript实现贪吃蛇小游戏
2019/11/25 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
2021/01/05 Vue.js
[02:30]联想杯DOTA2完美世界全国高校联赛—北京站现场
2015/11/16 DOTA
Python中的进程分支fork和exec详解
2015/04/11 Python
python使用socket连接远程服务器的方法
2015/04/29 Python
matplotlib简介,安装和简单实例代码
2017/12/26 Python
简单实现python收发邮件功能
2018/01/05 Python
Python读取指定日期邮件的实例
2019/02/01 Python
Python GUI编程 文本弹窗的实例
2019/06/11 Python
设置jupyter中DataFrame的显示限制方式
2020/04/12 Python
通过python 执行 nohup 不生效的解决
2020/04/16 Python
Python实例方法、类方法、静态方法区别详解
2020/09/05 Python
Grid 宫格常用布局的实现
2020/01/10 HTML / CSS
HTML5对手机页面长按会粘贴复制禁用的解决方法
2016/07/19 HTML / CSS
论文评语大全
2014/04/29 职场文书
会计求职自荐信
2014/06/20 职场文书
党的群众路线教育实践活动对照检查材料范文
2014/09/24 职场文书
毕业论文答辩开场白和答辩技巧
2015/05/27 职场文书
肖申克的救赎观后感
2015/06/02 职场文书
使用Selenium实现微博爬虫(预登录、展开全文、翻页)
2021/04/13 Python
Python turtle编写简单的球类小游戏
2022/03/31 Python
Elasticsearch Recovery 详细介绍
2022/04/19 Java/Android