举例讲解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合并字典键值并去除重复元素的实例
Dec 18 Python
使用Python实现博客上进行自动翻页
Aug 23 Python
Python内置模块turtle绘图详解
Dec 09 Python
浅谈python编译pyc工程--导包问题解决
Mar 20 Python
python实现最大子序和(分治+动态规划)
Jul 05 Python
python扫描线填充算法详解
Feb 19 Python
python tqdm 实现滚动条不上下滚动代码(保持一行内滚动)
Feb 19 Python
Python3.7.0 Shell添加清屏快捷键的实现示例
Mar 23 Python
Python GUI编程学习笔记之tkinter界面布局显示详解
Mar 30 Python
Python decorator拦截器代码实例解析
Apr 04 Python
python脚本和网页有何区别
Jul 02 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
Mar 03 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
PHP 数据库树的遍历方法
2009/02/06 PHP
php面向对象全攻略 (十六) 对象的串行化
2009/09/30 PHP
PHP使用xmllint命令处理xml与html的方法
2014/12/15 PHP
又十个超级有用的PHP代码片段
2015/09/24 PHP
Js的MessageBox
2006/12/03 Javascript
JavaScript 私有成员分析
2009/01/13 Javascript
window.onbeforeunload方法在IE下无法正常工作的解决办法
2010/01/23 Javascript
利用腾讯的ip地址库做ip物理地址定位
2010/07/24 Javascript
基于jquery的横向滚动条(滑动条)
2011/02/24 Javascript
JS 获取浏览器和屏幕宽高等信息代码
2014/03/31 Javascript
常见的jQuery选择器汇总
2014/11/24 Javascript
AngularJS中$interval的用法详解
2016/02/02 Javascript
javascript获取wx.config内部字段解决微信分享
2016/03/09 Javascript
js和C# 时间日期格式转换的简单实例
2016/05/28 Javascript
jquery uploadify隐藏上传进度的实现方法
2017/02/06 Javascript
Vue.js 2.0 移动端拍照压缩图片预览及上传实例
2017/04/27 Javascript
vue移动端裁剪图片结合插件Cropper的使用实例代码
2017/07/10 Javascript
React Native react-navigation 导航使用详解
2017/12/01 Javascript
使用classList来实现两个按钮样式的切换方法
2018/01/24 Javascript
Vue项目分环境打包的实现步骤
2018/04/02 Javascript
详解小程序不同页面之间通讯的解决方案
2018/11/23 Javascript
layui 中select下拉change事件失效的解决方法
2019/09/20 Javascript
vue elementui 实现搜索栏公共组件封装的实例代码
2020/01/20 Javascript
Django集成百度富文本编辑器uEditor攻略
2014/07/04 Python
Python实现的简单算术游戏实例
2015/05/26 Python
在Django的视图中使用form对象的方法
2015/07/18 Python
Python命令启动Web服务器实例详解
2017/02/23 Python
Python中psutil的介绍与用法
2019/05/02 Python
django 通过URL访问上传的文件方法
2019/07/28 Python
Django 源码WSGI剖析过程详解
2019/08/05 Python
基于python图像处理API的使用示例
2020/04/03 Python
Django在Model保存前记录日志实例
2020/05/14 Python
浅谈多卡服务器下隐藏部分 GPU 和 TensorFlow 的显存使用设置
2020/06/30 Python
html5中嵌入视频自动播放的问题解决
2020/05/25 HTML / CSS
澳洲网红粉泥面膜:Sand & Sky
2019/08/13 全球购物