python实现观察者模式

前言

  有时,我们希望在一个对象的状态改变时更新另外一组对象。在MVC模式中有这样一个非
常常见的例子,假设在两个视图(例如,一个饼图和一个电子表格)中使用同一个模型的数据,
无论何时更改了模型,都需要更新两个视图。这就是观察者设计模式要处理的问题(请参考
[Eckel08,第213页])。
  观察者模式描述单个对象(发布者,又称为主持者或可观察者)与一个或多个对象(订阅者,
又称为观察者)之间的发布 — 订阅关系。在MVC例子中,发布者是模型,订阅者是视图。然而,
MVC并非是仅有的发布 — 订阅例子。信息聚合订阅(比如,RSS或Atom)是另一种例子。许多读
者通常会使用一个信息聚合阅读器订阅信息流,每当增加一条新信息时,他们就能自动地获取到
更新。
  观察者模式背后的思想等同于MVC和关注点分离原则背后的思想,即降低发布者与订阅者
之间的耦合度,从而易于在运行时添加/删除订阅者。此外,发布者不关心它的订阅者是谁。它
只是将通知发送给所有订阅者(请参考[GOF95,第327页])。

介绍

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

应用案例

当我们希望在一个对象(主持者/发布者/可观察者)发生变化时通知/更新另一个或多个对象
的时候,通常会使用观察者模式。观察者的数量以及谁是观察者可能会有所不同,也可以(在运
行时)动态地改变。
  可以想到许多观察者模式在其中有用武之地的案例。本章开头已提过这样的一个案例,就是
信息聚合。无论格式为RSS、Atom还是其他,思想都一样:你追随某个信息源,当它每次更新时,
你都会收到关于更新的一个通知(请参考[Zlobin13,第60页])。

  同样的概念也存在于社交网络。如果你使用社交网络服务关联了另一个人,在关联的人更新
某些内容时,你能收到相关通知,不论这个关联的人是你关注的一个Twitter用户,Facebook上的
一个真实朋友,还是LinkdIn上的一位同事。
  事件驱动系统是另一个可以使用(通常也会使用)观察者模式的例子。在这种系统中,监听
者被用于监听特定事件。监听者正在监听的事件被创建出来时,就会触发它们。这个事件可以是
键入(键盘的)某个特定键、移动鼠标或者其他。事件扮演发布者的角色,监听者则扮演观察者
的角色。在这里,关键点是单个事件(发布者)可以关联多个监听者(观察者),请参考网页
[t.cn/Rqr1Xgj]。

实现

  我们将实现一个数据格式化程序。这里描述的想法来源于ActiveState网站上观察者
模式用法的Python代码实现(请参考网页[t.cn/Rqr1SDO])。默认格式化程序是以十进制格式展
示一个数值。然而,我们可以添加/注册更多的格式化程序。这个例子中将添加一个十六进制格
式化程序和一个二进制格式化程序。每次更新默认格式化程序的值时,已注册的格式化程序就会
收到通知,并采取行动。在这里,行动就是以相关的格式展示新的值。
  在一些模式中,继承能体现自身价值,观察者模式是这些模式中的一个。我们可以实现一个
基类 Publisher ,包括添加、删除及通知观察者这些公用功能。 DefaultFormatter 类继承自
Publisher ,并添加格式化程序特定的功能。我们可以按需动态地添加删除观察者。下面的类图
展示了一个使用两个观察者( HexFormatter 和 BinaryFormatter )的示例。注意,因为类图
是静态的,所以无法展示系统的整个生命周期,只能展示某个特定时间点的系统状态。

#  observers存储观察者
# add()方法注册一个新的观察者
# remove()方法注销一个已有的观察者
# notify() 方法则在变化发生时通知所有观察者。
class Publisher:
def __init__(self):
self.observers = []
def add(self, observer):
if observer not in self.observers:
self.observers.append(observer)
else:
print('Failed to add: {}'.format(observer))
def remove(self, observer):
try:
self.observers.remove(observer)
except ValueError:
print('Failed to remove: {}'.format(observer))
def notify(self):
[o.notify(self) for o in self.observers] # __str__() 方法返回关于发布者名称和 _data 值的信息。
# 第一个使用 @property 修饰器来提供 _data 变量的读访问方式。这样,我们就能使用 object.data 来替代 object.data() 。
# 第二个 data() 更有意思。它使用了 @setter 修饰器,该修饰器会在每次使用赋值操作符( = ) 为 _data 变量赋新值时被调用。
class DefaultFormatter(Publisher):
def __init__(self, name):
Publisher.__init__(self)
self.name = name
self._data = 0
def __str__(self):
return "{}: '{}' has data = {}".format(type(self).__name__, self.name,self._data)
@property
def data(self):
return self._data
@data.setter
def data(self, new_value):
try:
self._data = int(new_value)
except ValueError as e:
print('Error: {}'.format(e))
else:
print("修改了")
self.notify() # 下一步是添加观察者。 HexFormatter 和 BinaryFormatter 的功能非常相似。唯一的不同
# 在于如何格式化从发布者那获取到的数据值,即分别以十六进制和二进制进行格式化。
class HexFormatter:
def notify(self, publisher):
print("{}: '{}' has now hex data = {}".format(type(self).__name__, publisher.name, hex(publisher.data)))
class BinaryFormatter:
def notify(self, publisher):
print("{}: '{}' has now bin data = {}".format(type(self).__name__,
publisher.name, bin(publisher.data))) def main():
df = DefaultFormatter('test1')
hf = HexFormatter()
bf = BinaryFormatter()
#添加观察者
df.add(hf)
df.add(bf)
#每次修改发布者的值,observers里面的观察者会调用notify()方法
df.data = 1
df.data = 10
#当把某个观察者踢出observers,当修改发布者的data值就不会通知这个观察者
df.remove(hf)
df.data = 6 if __name__ == '__main__':
main()

python实现观察者模式的更多相关文章

  1. 大话设计模式Python实现-观察者模式

    观察者模式(发布-订阅模式 Publish Subscribe Pattern):定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者,是它们能够自动更 ...

  2. Python设计模式——观察者模式

    需求:员工上班在偷偷看股票,拜托前台一旦老板进来,就通知他们,让他们停止看股票. 这里有两类人,一类是观察者,即员工,一类是通知者,即前台,员工在观察前台的状态,前台负责通知员工最新的动态. #enc ...

  3. [python实现设计模式]-4.观察者模式-吃食啦!

    观察者模式是一个非常重要的设计模式. 我们先从一个故事引入. 工作日的每天5点左右,大燕同学都会给大家订饭. 然后7点左右,饭来了. 于是燕哥大吼一声,“饭来啦!”,5点钟定过饭的同学就会纷纷涌入餐厅 ...

  4. python设计模式之观察者模式

    观察者模式 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern).比如,当一个对象被修改时,则会自动通知它的依赖对象.观察者模式属于行为型模式. 观察者模式在状态检测和事件处 ...

  5. python设计模式第十天【观察者模式】

    1.应用场景 (1)监听事件驱动程序中的外部事件 (2)监听某个对象的状态变化 (3)发布-订阅模型中,消息出现时通知邮件列表中的订阅者 2. 观察者模式UML图 3. 代码实现: #!/usr/bi ...

  6. 设计模式(Python)-观察者模式

    本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题: 为什么?即为什么要使用这个设计模式,在使用这个模式之前存在什么样的 ...

  7. python 设计模式之观察者模式

    观察者模式是一个软件设计模式,一个主题对象博包涵一系列依赖他的观察者,自动通知观察者的主题对象的改变,通常会调用每个观察者的一个方法.这个设计模式非常适用于分布式事件处理系统. 典型的在观察者模式下: ...

  8. python设计模式---行为型之观察者模式

    比较常用咯~~ from django.test import TestCase from abc import ABCMeta, abstractmethod # 行为型设计模式---观察者模式 c ...

  9. 观察者模式的python实现

    什么会观察者模式?观察者模式就是订阅-推送模式.是为了解耦合才会被利用起来的设计模式. 经典的就是boss 前台和员工之间的故事.一天A员工在看电影,B员工在看动漫,但是两人担心boss来了,自己没及 ...

随机推荐

  1. 【Linux】单计算机安装PBS系统(Torque)与运维

    1.此次使用torque-5.0.0-1_43d8f09a.tar.gz这个版本http://www.adaptivecomputing.com/downloading/?file=/torque/t ...

  2. Entity Framework Code First使用者的福音 --- EF Power Tool使用记之一

    下次会为大家深入解析这个小工具.  最先看到这个工具是在EF产品组最新的博客文章上,http://blogs.msdn.com/b/adonet/archive/2011/05/18/ef-power ...

  3. IP处理模块IPy

    #安装IPy模块#pip install IPy #from IPy import IPip_s = input('please input an IP or net-range:')#192.168 ...

  4. leetcode-easy-listnode-141 Linked List Cycle

    mycode  98.22% # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x ...

  5. T83312 【音乐会】达拉崩吧·上

    T83312 [音乐会]达拉崩吧·上 题解 线段树板子题 把原来的 + 变成 ^ 但是注意一下懒标记,这里讲一下小技巧 代码 #include<bits/stdc++.h> using n ...

  6. idea 编译 brooklin

    gradle 项目导入 idea 之后,各种报错,run 不起来 手动加入各种依赖 配置启动类 指定 log4j.properties

  7. opengl入门篇二: 索引缓冲对象EBO

    在绘制图形的过程中,顶点可能会重复.比如两个三角形组成了四边形,那么,必然有两个点是重复的.因此采用索引的方式,四个点即可描述四边形. // 四个顶点 GLfloat vertices[] = { / ...

  8. 关于springmvc的一些注解详解

    引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时,发现服务器端接受不到提交的数据(服务器端参数绑定没有加任何注解),查看了提交方式为applicatio ...

  9. Elasticsearch 6.2.3版本 同一个index新增type报错 Rejecting mapping update to [website] as the final mapping would have more than 1 type: [blog2, blog]

    在website的index下已经存在一个名为blog的type.想在website下,新增一个名为blog2的type. 执行语句如下: PUT /website/blog2/1 { "t ...

  10. 收货确定 BAPI BAPI_GOODSMVT_CREATE

    CLEAR gmhead.     gmhead-pstng_date = ls_table-gzdate."sy-datum .     gmhead-doc_date = sy-datu ...