举例讲解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实现抓取页面上链接的简单爬虫分享
Jan 21 Python
详解Python中的静态方法与类成员方法
Feb 28 Python
在python中将字符串转为json对象并取值的方法
Dec 31 Python
python 实现将小图片放到另一个较大的白色或黑色背景图片中
Dec 12 Python
python离线安装外部依赖包的实现
Feb 13 Python
Python数组并集交集补集代码实例
Feb 18 Python
python实现处理mysql结果输出方式
Apr 09 Python
解决matplotlib.pyplot在Jupyter notebook中不显示图像问题
Apr 22 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
May 18 Python
Python生成器generator原理及用法解析
Jul 20 Python
anaconda3安装及jupyter环境配置全教程
Aug 24 Python
Python中tqdm的使用和例子
Sep 23 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目录函数实现创建、读取目录教程实例
2011/01/13 PHP
php防止sql注入示例分析和几种常见攻击正则表达式
2014/01/12 PHP
PHP中使用strpos函数实现屏蔽敏感关键字功能
2014/08/21 PHP
CI框架中类的自动加载问题分析
2016/11/21 PHP
PHP实现添加购物车功能
2017/03/06 PHP
kindeditor 加入七牛云上传的实例讲解
2017/11/12 PHP
javascript 学习笔记(八)javascript对象
2011/04/12 Javascript
jquery中的 $("#jb51")与document.getElementById("jb51") 的区别
2011/07/26 Javascript
使用jQuery清空file文件域的解决方案
2013/04/12 Javascript
js使用eval解析json(js中使用json)
2014/01/17 Javascript
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
JS中使用apply方法通过不同数量的参数调用函数的方法
2016/05/31 Javascript
jQuery.form.js插件不能解决连接超时(timeout)的原因分析及解决方法
2016/10/14 Javascript
js实现点击按钮弹出上传文件的窗口
2016/12/23 Javascript
Angularjs实现分页和分页算法的示例代码
2016/12/23 Javascript
js+html5实现侧滑页面效果
2017/07/15 Javascript
Taro集成Redux快速上手的方法示例
2018/06/21 Javascript
微信小程序实现带缩略图轮播效果
2018/11/04 Javascript
JS图片懒加载技术实现过程解析
2020/07/27 Javascript
js简单粗暴的发布订阅示例代码
2021/01/23 Javascript
深入理解Python爬虫代理池服务
2018/02/28 Python
深入浅析Python传值与传址
2018/07/10 Python
Python中xml和json格式相互转换操作示例
2018/12/05 Python
python读取目录下最新的文件夹方法
2018/12/24 Python
Python 给下载文件显示进度条和下载时间的实现
2020/04/02 Python
python 一维二维插值实例
2020/04/22 Python
解决Keras使用GPU资源耗尽的问题
2020/06/22 Python
解析Python 偏函数用法全方位实现
2020/06/26 Python
HTML5实现一个能够移动的小坦克示例代码
2013/09/02 HTML / CSS
日本著名化妆品零售网站:Cosme Land
2019/03/01 全球购物
C++:局部变量能否和全局变量重名
2014/03/03 面试题
门卫班长岗位职责
2013/12/15 职场文书
医学专业大学生求职信
2014/07/12 职场文书
四年级学生期末评语
2014/12/26 职场文书
2015年入党决心书
2015/02/05 职场文书
公务员爱岗敬业心得体会
2016/01/25 职场文书