举例讲解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实现RSA加密(解密)算法
Feb 17 Python
Python实现控制台中的进度条功能代码
Dec 22 Python
Python cookbook(数据结构与算法)字典相关计算问题示例
Feb 18 Python
Python设计模式之状态模式原理与用法详解
Jan 15 Python
搞清楚 Python traceback的具体使用方法
May 13 Python
Python Django view 两种return的实现方式
Mar 16 Python
Python虚拟环境venv用法详解
May 25 Python
解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题
Jul 02 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
Sep 04 Python
pycharm2021激活码使用教程(永久激活亲测可用)
Mar 30 Python
Python序列化与反序列化相关知识总结
Jun 08 Python
Python Django ORM连表正反操作技巧
Jun 13 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
php5.5中类级别的常量使用介绍
2013/10/02 PHP
Thinkphp3.2.3整合phpqrcode生成带logo的二维码
2016/07/21 PHP
Laravel关系模型指定条件查询方法
2019/10/10 PHP
<script defer> defer 是什么意思
2009/05/10 Javascript
Windows 系统下安装和部署Egret的开发环境
2014/07/31 Javascript
Nodejs极简入门教程(一):模块机制
2014/10/25 NodeJs
js中iframe调用父页面的方法
2014/10/30 Javascript
JavaScript模拟数组合并concat
2016/03/06 Javascript
浅谈jQuery中ajaxPrefilter的应用
2016/08/01 Javascript
jQuery制作圣诞主题页面 更像是爱情影集
2016/08/10 Javascript
Javascript使用SWFUpload进行多文件上传
2016/11/16 Javascript
使用JS实现气泡跟随鼠标移动的动画效果
2017/09/16 Javascript
详解AngularJS之$window窗口对象
2018/01/17 Javascript
剖析Angular Component的源码示例
2018/03/23 Javascript
JS中promise化微信小程序api
2018/04/12 Javascript
微信小程序排坑指南详解
2018/05/23 Javascript
Nodejs技巧之Exceljs表格操作用法示例
2019/11/06 NodeJs
vue-property-decorator用法详解
2019/12/12 Javascript
ES6 Symbol在对象中的作用实例分析
2020/06/06 Javascript
echarts实现晶体球面投影的实例教程
2020/10/10 Javascript
JavaScript实现HTML导航栏下拉菜单
2020/11/25 Javascript
详解在Python中处理异常的教程
2015/05/24 Python
恢复百度云盘本地误删的文件脚本(简单方法)
2017/10/21 Python
Python二叉树的定义及常用遍历算法分析
2017/11/24 Python
对pycharm代码整体左移和右移缩进快捷键的介绍
2018/07/16 Python
Python多继承以及MRO顺序的使用
2019/11/11 Python
Pytorch中.new()的作用详解
2020/02/18 Python
Scrapy基于scrapy_redis实现分布式爬虫部署的示例
2020/09/29 Python
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
2016/08/18 面试题
挂牌仪式主持词
2014/03/20 职场文书
任命书范本大全
2014/06/06 职场文书
学校四风问题对照检查材料思想汇报
2014/09/26 职场文书
端午节活动总结报告
2015/02/11 职场文书
地震捐款简报
2015/07/21 职场文书
Windows server 2003卸载和安装IIS的图文教程
2022/07/15 Servers
mysqldump进行数据备份详解
2022/07/15 MySQL