举例讲解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 相关文章推荐
Pyramid将models.py文件的内容分布到多个文件的方法
Nov 27 Python
python实现在每个独立进程中运行一个函数的方法
Apr 23 Python
使用Python编写简单的端口扫描器的实例分享
Dec 18 Python
Python MD5加密实例详解
Aug 02 Python
python3解析库lxml的安装与基本使用
Jun 27 Python
python爬虫自动创建文件夹的功能
Aug 01 Python
python判断输入日期为第几天的实例
Nov 13 Python
python opencv进行图像拼接
Mar 27 Python
Django Admin后台添加数据库视图过程解析
Apr 01 Python
Python函数的迭代器与生成器的示例代码
Jun 18 Python
Python基于argparse与ConfigParser库进行入参解析与ini parser
Feb 02 Python
python基于tkinter制作下班倒计时工具
Apr 28 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高自定义性安全验证码代码
2011/11/27 PHP
基于Zend的Config机制的应用分析
2013/05/02 PHP
php中有关字符串的4个函数substr、strrchr、strstr、ereg介绍和使用例子
2014/04/24 PHP
JS JavaScript获取Url参数,src属性参数
2021/03/09 Javascript
动态调用CSS文件的JS代码
2010/07/29 Javascript
JQuery入门—JQuery程序的代码风格详细介绍
2013/01/03 Javascript
javascript实现滑动解锁功能
2014/12/31 Javascript
jQuery实现新消息闪烁标题提示的方法
2015/03/11 Javascript
AngularJS中的过滤器使用详解
2015/06/16 Javascript
利用jQuery及AJAX技术定时更新GridView的某一列数据
2015/12/04 Javascript
属于你的jQuery提示框(Tip)插件
2016/01/20 Javascript
JavaScript随机打乱数组顺序之随机洗牌算法
2016/08/02 Javascript
nodejs 生成和导出 word的实例代码
2018/07/31 NodeJs
详解key在Vue列表渲染时究竟起到了什么作用
2019/04/20 Javascript
windows下create-react-app 升级至3.3.1版本踩坑记
2020/02/17 Javascript
Python2.6版本中实现字典推导 PEP 274(Dict Comprehensions)
2015/04/28 Python
SQLite3中文编码 Python的实现
2017/01/11 Python
Python tkinter模块中类继承的三种方式分析
2017/08/08 Python
Python实现桶排序与快速排序算法结合应用示例
2017/11/22 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
基于MTCNN/TensorFlow实现人脸检测
2018/05/24 Python
Python中asyncio与aiohttp入门教程
2018/10/16 Python
Django框架 querySet功能解析
2019/09/04 Python
详解Pytorch显存动态分配规律探索
2020/11/17 Python
Python操作Excel的学习笔记
2021/02/18 Python
CSS3对背景图片的裁剪及尺寸和位置的设定方法
2016/03/07 HTML / CSS
自我评价怎么写正确呢?
2013/12/02 职场文书
马云的职业生涯规划之路
2014/01/01 职场文书
大学生个人实习的自我评价
2014/02/15 职场文书
课前三分钟演讲稿
2014/04/24 职场文书
2016年记者节感言
2015/12/08 职场文书
基于Redis实现分布式锁的方法(lua脚本版)
2021/05/12 Redis
MySql开发之自动同步表结构
2021/05/28 MySQL
SpringBoot中HttpSessionListener的简单使用方式
2022/03/17 Java/Android
使用Nginx+Tomcat实现负载均衡的全过程
2022/05/30 Servers
mysql sock 文件解析及作用讲解
2022/07/15 MySQL