举例讲解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中的filter()函数的用法
Apr 27 Python
在Django中创建动态视图的教程
Jul 15 Python
Matplotlib 生成不同大小的subplots实例
May 25 Python
windows下python 3.6.4安装配置图文教程
Aug 21 Python
python引入不同文件夹下的自定义模块方法
Oct 27 Python
Python 函数返回值的示例代码
Mar 11 Python
python安装requests库的实例代码
Jun 25 Python
Python异常继承关系和自定义异常实现代码实例
Feb 20 Python
python中get和post有什么区别
Jun 19 Python
keras的ImageDataGenerator和flow()的用法说明
Jul 03 Python
Django-silk性能测试工具安装及使用解析
Nov 28 Python
用python爬虫批量下载pdf的实现
Dec 01 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
ThinkPHP之import方法实例详解
2014/06/20 PHP
PHP中使用json数据格式定义字面量对象的方法
2014/08/20 PHP
PHP中include/require/include_once/require_once使用心得
2016/08/28 PHP
什么是PHP7中的孤儿进程与僵尸进程
2019/04/14 PHP
JQuery datepicker 使用方法
2011/05/20 Javascript
fancybox modal的完美解决(右上的X)
2012/10/30 Javascript
seajs1.3.0源码解析之module依赖有序加载
2012/11/07 Javascript
深入理解javascript作用域和闭包
2014/09/23 Javascript
详解 javascript中offsetleft属性的用法
2015/11/11 Javascript
AngularJS 过滤与排序详解及实例代码
2016/09/14 Javascript
vue2.0+vue-dplayer实现hls播放的示例
2018/03/02 Javascript
详解webpack-dev-middleware 源码解读
2020/03/23 Javascript
基于JS实现计算24点算法代码实例解析
2020/07/23 Javascript
使用python的chardet库获得文件编码并修改编码
2014/01/22 Python
python实现ipsec开权限实例
2014/11/11 Python
python定时执行指定函数的方法
2015/05/27 Python
Python中摘要算法MD5,SHA1简介及应用实例代码
2018/01/09 Python
Python网络爬虫中的同步与异步示例详解
2018/02/03 Python
pyqt5 实现多窗口跳转的方法
2019/06/19 Python
django如何通过类视图使用装饰器
2019/07/24 Python
Python读入mnist二进制图像文件并显示实例
2020/04/24 Python
Python退出时强制运行一段代码的实现方法
2020/04/29 Python
解决Keras TensorFlow 混编中 trainable=False设置无效问题
2020/06/28 Python
Python爬虫新手入门之初学lxml库
2020/12/20 Python
纯css3实现效果超级炫的checkbox复选框和radio单选框
2014/09/01 HTML / CSS
Jabra捷波朗美国官网:用于办公、车载和运动的无线蓝牙耳麦
2017/02/01 全球购物
HOTEL INFO英国:搜索全球酒店
2019/08/08 全球购物
htmlentities() 和 htmlspecialchars()有什么区别
2015/07/01 面试题
会计岗位职责
2013/11/08 职场文书
自我评价200字分享
2013/12/17 职场文书
自荐信需注意事项
2014/01/25 职场文书
《地震中的父与子》教学反思
2014/04/10 职场文书
10的分与合教学反思
2014/04/30 职场文书
患者身份识别制度
2015/08/06 职场文书
2016年三八红旗手先进事迹材料
2016/02/26 职场文书
Windows7下FTP搭建图文教程
2022/08/05 Servers