举例讲解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运行效率的方法之间的对比
Apr 03 Python
python安装教程 Pycharm安装详细教程
May 02 Python
详解python中 os._exit() 和 sys.exit(), exit(0)和exit(1) 的用法和区别
Jun 23 Python
python:print格式化输出到文件的实例
May 14 Python
Python中正反斜杠(‘/’和‘\’)的意义与用法
Aug 12 Python
python 实现return返回多个值
Nov 19 Python
OpenCV+Python--RGB转HSI的实现
Nov 27 Python
Python3如何在Windows和Linux上打包
Feb 25 Python
Python 改变数组类型为uint8的实现
Apr 09 Python
python3+openCV 获取图片中文本区域的最小外接矩形实例
Jun 02 Python
如何在Python项目中引入日志
May 31 Python
python基础之错误和异常处理
Oct 24 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 连接mysql连接被重置的解决方法
2011/02/15 PHP
PhpMyAdmin出现export.php Missing parameter: what /export_type错误解决方法
2012/08/09 PHP
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
2015/11/15 PHP
sina的lightbox效果。
2007/01/09 Javascript
基于jQuery的试卷自动排版系统实现代码
2011/01/06 Javascript
浅析JavaScript中的隐式类型转换
2013/12/05 Javascript
jQuery 隐藏和显示 input 默认值示例
2014/06/03 Javascript
JS生成随机字符串的多种方法
2014/06/10 Javascript
js+html5实现canvas绘制圆形图案的方法
2015/06/05 Javascript
jquery不常用方法汇总
2015/07/26 Javascript
Immutable 在 JavaScript 中的应用
2016/05/02 Javascript
sso跨域写cookie的一段js脚本(推荐)
2016/05/25 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
2016/09/01 Javascript
jQuery实现鼠标跟随效果
2017/02/20 Javascript
Angular.js之作用域scope'@','=','&'实例详解
2017/02/28 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题
2018/08/24 Javascript
解决layui下拉框监听问题(监听不到值的变化)
2019/09/28 Javascript
JSONP 的原理、理解 与 实例分析
2020/05/16 Javascript
原生js实现简单轮播图
2020/10/26 Javascript
python利用hook技术破解https的实例代码
2013/03/25 Python
python中split方法用法分析
2015/04/17 Python
python之消除前缀重命名的方法
2018/10/21 Python
python2.7 安装pip的方法步骤(管用)
2019/05/05 Python
CSS3中Transform动画属性用法详解
2016/07/04 HTML / CSS
详解CSS3中nth-child与nth-of-type的区别
2017/01/05 HTML / CSS
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
共产党员承诺书
2014/03/25 职场文书
党建工作经验交流材料
2014/05/25 职场文书
物理课外活动总结
2014/08/27 职场文书
感恩老师演讲稿600字
2014/08/28 职场文书
2014入党积极分子批评与自我批评思想汇报
2014/09/20 职场文书
关于艺术节的开幕致辞
2016/03/04 职场文书
详解Mysql 函数调用优化
2021/04/07 MySQL
Redis 的查询很快的原因解析及Redis 如何保证查询的高效
2022/03/16 Redis
vue 给数组添加新对象并赋值
2022/04/20 Vue.js