举例讲解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 相关文章推荐
Flask入门教程实例:搭建一个静态博客
Mar 27 Python
python发送邮件功能实现代码
Jul 15 Python
python利用Guetzli批量压缩图片
Mar 23 Python
Python实现的knn算法示例
Jun 14 Python
pytorch permute维度转换方法
Dec 14 Python
python Pexpect 实现输密码 scp 拷贝的方法
Jan 03 Python
利用python实现对web服务器的目录探测的方法
Feb 26 Python
Python获取数据库数据并保存在excel表格中的方法
Jun 12 Python
Django自定义列表 models字段显示方式
Apr 03 Python
python 实现分组求和与分组累加求和代码
May 18 Python
Python基于数列实现购物车程序过程详解
Jun 09 Python
python 窃取摄像头照片的实现示例
Jan 08 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/10/09 PHP
用libtemplate实现静态网页生成
2006/10/09 PHP
一个PHP并发访问实例代码
2012/09/06 PHP
Ubuntu12下编译安装PHP5.3开发环境
2015/03/27 PHP
PHP+redis实现的购物车单例类示例
2019/02/02 PHP
laravel 解决ajax异步提交数据,并还回填充表格的问题
2019/10/15 PHP
laravel框架分组控制器和分组路由实现方法示例
2020/01/25 PHP
JS获取父节点方法
2009/08/20 Javascript
2010年最佳jQuery插件整理
2010/12/06 Javascript
javascript拖拽效果延伸学习
2016/04/04 Javascript
js仿3366小游戏选字游戏
2016/04/14 Javascript
AngularJS ng-blur 指令详解及简单实例
2016/07/30 Javascript
Node.js包管理器Yarn的入门介绍与安装
2016/10/17 Javascript
JS中cookie的使用及缺点讲解
2017/05/13 Javascript
js使用文件流下载csv文件的实现方法
2019/07/15 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
2019/11/01 jQuery
js 函数性能比较方法
2020/08/24 Javascript
深入理解python中的闭包和装饰器
2016/06/12 Python
Python 3.x基于Xml数据的Http请求方法
2018/12/28 Python
对python中Librosa的mfcc步骤详解
2019/01/09 Python
python可视化实现代码
2019/01/15 Python
python实现批量nii文件转换为png图像
2019/07/18 Python
Python自动化导出zabbix数据并发邮件脚本
2019/08/16 Python
Python高级特性之闭包与装饰器实例详解
2019/11/19 Python
基于django 的orm中非主键自增的实现方式
2020/05/18 Python
关于box-sizing的全面理解
2016/07/28 HTML / CSS
HTML5中的进度条progress元素简介及兼容性处理
2016/06/02 HTML / CSS
英国领先的办公用品供应商:Viking
2016/08/01 全球购物
MAC彩妆英国官网:M·A·C UK
2018/05/30 全球购物
几道数据库的面试题或笔试题
2014/05/31 面试题
2014年环境卫生工作总结
2014/11/24 职场文书
高三化学教学反思
2016/02/22 职场文书
k-means & DBSCAN 总结
2021/04/27 Python
OpenCV-Python实现轮廓拟合
2021/06/08 Python
MySQL系列之十四 MySQL的高可用实现
2021/07/02 MySQL
关于PHP数组迭代器的使用方法实例
2021/11/17 PHP