举例讲解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使用cookielib库示例分享
Mar 03 Python
详解python发送各类邮件的主要方法
Dec 22 Python
Python中第三方库Requests库的高级用法详解
Mar 12 Python
解析Python中的eval()、exec()及其相关函数
Dec 20 Python
python3+PyQt5使用数据库表视图
Apr 24 Python
python实现判断一个字符串是否是合法IP地址的示例
Jun 04 Python
python 字典操作提取key,value的方法
Jun 26 Python
python代理工具mitmproxy使用指南
Jul 04 Python
Python实现一个带权无回置随机抽选函数的方法
Jul 24 Python
使用OpenCV实现仿射变换—缩放功能
Aug 29 Python
Python二元算术运算常用方法解析
Sep 15 Python
Django mysqlclient安装和使用详解
Sep 17 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
人族 Terran 基本策略
2020/03/14 星际争霸
PHP的类 功能齐全的发送邮件类
2006/10/09 PHP
php chr() ord()中文截取乱码问题解决方法
2008/09/08 PHP
php批量上传的实现代码
2013/06/09 PHP
用HTML/JS/PHP方式实现页面延时跳转的简单实例
2016/07/18 PHP
PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
2018/07/17 PHP
js 图片缩放(按比例)控制代码
2009/05/27 Javascript
firefox火狐浏览器与与ie兼容的2个问题总结
2010/07/20 Javascript
jquery autocomplete自动完成插件的的使用方法
2010/08/07 Javascript
jQuery学习总结之元素的相对定位和选择器(持续更新)
2011/04/26 Javascript
两款JS脚本判断手机浏览器类型跳转WAP手机网站
2015/10/16 Javascript
JavaScript获取当前url根目录(路径)
2016/06/17 Javascript
javascript使用 concat 方法对数组进行合并的方法
2016/09/08 Javascript
Bootstrap中glyphicons-halflings-regular.woff字体报404错notfound的解决方法
2017/01/19 Javascript
jQuery修改DOM结构_动力节点Java学院整理
2017/07/05 jQuery
关于angularJs清除浏览器缓存的方法
2017/11/28 Javascript
剖析Angular Component的源码示例
2018/03/23 Javascript
修改node.js默认的npm安装目录实例
2018/05/15 Javascript
ios中视频的最后一桢问题解决
2019/05/14 Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
2019/07/20 Javascript
Vue+Koa2+mongoose写一个像素绘板的实现方法
2019/09/10 Javascript
layui问题之模拟table表格中的选中按钮选中事件的方法
2019/09/20 Javascript
基于vue.js实现购物车
2020/01/15 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
2020/06/24 jQuery
小程序实现简单语音聊天的示例代码
2020/07/24 Javascript
小程序实现列表倒计时功能
2021/01/29 Javascript
python在linux中输出带颜色的文字的方法
2014/06/19 Python
python 使用sys.stdin和fileinput读入标准输入的方法
2018/10/17 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
详解Python 多线程 Timer定时器/延迟执行、Event事件
2019/06/27 Python
pytorch方法测试详解——归一化(BatchNorm2d)
2020/01/15 Python
numpy 矩阵形状调整:拉伸、变成一位数组的实例
2020/06/18 Python
详解如何用HTML5 Canvas API控制图片的缩放变换
2016/03/22 HTML / CSS
Footshop法国:购买运动鞋
2020/01/19 全球购物
物业电工岗位职责
2013/11/20 职场文书
意向书范文
2014/03/31 职场文书