举例讲解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自动化测试之从命令行运行测试用例with verbosity
Sep 28 Python
浅谈编码,解码,乱码的问题
Dec 30 Python
详解Pytorch 使用Pytorch拟合多项式(多项式回归)
May 24 Python
Python mutiprocessing多线程池pool操作示例
Jan 30 Python
详解pandas.DataFrame中删除包涵特定字符串所在的行
Apr 04 Python
机器学习实战之knn算法pandas
Jun 22 Python
bluepy 一款python封装的BLE利器简单介绍
Jun 25 Python
Django 大文件下载实现过程解析
Aug 01 Python
Python函数参数类型及排序原理总结
Dec 19 Python
python super用法及原理详解
Jan 20 Python
详解Python中@staticmethod和@classmethod区别及使用示例代码
Dec 14 Python
简单且有用的Python数据分析和机器学习代码
Jul 02 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
关于时间计算的结总
2006/12/06 PHP
解决PHP4.0 和 PHP5.0类构造函数的兼容问题
2013/08/01 PHP
php中青蛙跳台阶的问题解决方法
2018/10/14 PHP
YII2框架使用控制台命令的方法分析
2020/03/18 PHP
Aster vs KG BO3 第一场2.18
2021/03/10 DOTA
飞鱼(shqlsl) javascript作品集
2006/12/16 Javascript
js触发asp.net的Button的Onclick事件应用
2013/02/02 Javascript
extjs_02_grid显示本地数据、显示跨域数据
2014/06/23 Javascript
jQuery中is()方法用法实例
2015/01/06 Javascript
JavaScript使用二分查找算法在数组中查找数据的方法
2015/04/07 Javascript
javascript中eval函数用法分析
2015/04/25 Javascript
js实现的动画导航菜单效果代码
2015/09/10 Javascript
jQuery中serializeArray()与serialize()的区别实例分析
2015/12/09 Javascript
理解JavaScript中worker事件api
2015/12/25 Javascript
JavaScript仿淘宝页面图片滚动加载及刷新回顶部的方法解析
2016/05/24 Javascript
JavaScript计时器用法分析【setTimeout和clearTimeout】
2017/01/18 Javascript
如何使用Bootstrap创建表单
2017/03/29 Javascript
JavaScript实现提交模式窗口后刷新父窗口数据的方法
2017/06/16 Javascript
利用types增强vscode中js代码提示功能详解
2017/07/07 Javascript
element-ui中select组件绑定值改变,触发change事件方法
2018/08/24 Javascript
react实现同页面三级跳转路由布局
2019/09/26 Javascript
[46:42]DOTA2-DPC中国联赛正赛 Aster vs Magma BO3 第二场 3月5日
2021/03/11 DOTA
python与php实现分割文件代码
2017/03/06 Python
解决Python中list里的中文输出到html模板里的问题
2018/12/17 Python
详解Selenium-webdriver绕开反爬虫机制的4种方法
2020/10/28 Python
HTML5 在canvas中绘制文本附效果图
2014/06/23 HTML / CSS
html5中canvas图表实现柱状图的示例
2017/11/13 HTML / CSS
采用专利算法搜索最廉价的机票:CheapAir
2016/09/10 全球购物
机电一体化自荐信
2013/12/10 职场文书
交通事故调解协议书
2014/04/16 职场文书
2014最新预备党员思想汇报范文:中国梦,我的梦
2014/10/25 职场文书
2014年学校食堂工作总结
2014/11/25 职场文书
2014年平安夜寄语
2014/12/08 职场文书
管理人员岗位职责
2015/02/14 职场文书
Python实战之大鱼吃小鱼游戏的实现
2022/04/01 Python
Nginx报错104:Connection reset by peer问题的解决及分析
2022/07/23 Servers