设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

设计模式 ( 十五 ) 观察者模式Observer(对象行为型)

  

1.概述

一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力。当对象们连接在一起时,它们就可以相互提供服务和信息。

通常来说,当某个对象的状态发生改变时,你仍然需要对象之间能互相通信。但是出于各种原因,你也许并不愿意因为代码环境的改变而对代码做大的修改。也许,你只想根据你的具体应用环境而改进通信代码。或者,你只想简单的重新构造通信代码来避免类和类之间的相互依赖与相互从属。

2.问题

当一个对象的状态发生改变时,你如何通知其他对象?是否需要一个动态方案――一个就像允许脚本的执行一样,允许自由连接的方案?

3.解决方案

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

观测模式允许一个对象关注其他对象的状态,并且,观测模式还为被观测者提供了一种观测结构,或者说是一个主体和一个客体。主体,也就是被观测者,可以用来联系所有的观测它的观测者。客体,也就是观测者,用来接受主体状态的改变 观测就是一个可被观测的类(也就是主题)与一个或多个观测它的类(也就是客体)的协作。不论什么时候,当被观测对象的状态变化时,所有注册过的观测者都会得到通知。
观测模式将被观测者(主体)从观测者(客体)种分离出来。这样,每个观测者都可以根据主体的变化分别采取各自的操作。(观测模式和Publish/Subscribe模式一样,也是一种有效描述对象间相互作用的模式。)观测模式灵活而且功能强大。对于被观测者来说,那些查询哪些类需要自己的状态信息和每次使用那些状态信息的额外资源开销已经不存在了。另外,一个观测者可以在任何合适的时候进行注册和取消注册。你也可以定义多个具体的观测类,以便在实际应用中执行不同的操作。
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。

 

4.适用性

在以下任一情况下可以使用观察者模式:
• 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
• 当对一个对象的改变需要同时改变其它对象 , 而不知道具体有多少对象有待改变。
• 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的。

5.结构

6.模式的组成

观察者模式包含如下角色:
目标(Subject): 目标知道它的观察者。可以有任意多个观察者观察同一个目标。 提供注册和删除观察者对象的接口。
具体目标(ConcreteSubject):  将有关状态存入各ConcreteObserver对象。
观察者(Observer):  为那些在目标发生改变时需获得通知的对象定义一个更新接口。当它的状态发生改变时, 向它的各个观察者发出通知。
具体观察者(ConcreteObserver):   维护一个指向ConcreteSubject对象的引用。存储有关状态,这些状态应与目标的状态保持一致。实现O b s e r v e r的更新接口以使自身状态与目标的状态保持一致。

7.效果

Observer模式允许你独立的改变目标和观察者。你可以单独复用目标对象而无需同时复用其观察者, 反之亦然。它也使你可以在不改动目标和其他的观察者的前提下增加观察者。
下面是观察者模式其它一些优点:
1 )观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
2 )在观察目标和观察者之间建立一个抽象的耦合 :一个目标所知道的仅仅是它有一系列观察者 , 每个都符合抽象的Observer类的简单接口。目标不知道任何一个观察者属于哪一个具体的类。这样目标和观察者之间的耦合是抽象的和最小的。因为目标和观察者不是紧密耦合的, 它们可以属于一个系统中的不同抽象层次。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知它 , 这样就保持了系统层次的完整。如果目标和观察者混在一块 ,
那么得到的对象要么横贯两个层次 (违反了层次性), 要么必须放在这两层的某一层中(这可能会损害层次抽象)。
3) 支持广播通信 :不像通常的请求, 目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣 ;它唯一的责任就是通知它的各观察者。这给了你在任何时刻增加和删除观察者的自由。处理还是忽略一个通知取决于观察者。
4) 观察者模式符合“开闭原则”的要求。
观察者模式的缺点
1) 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2) 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3) 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
4)  意外的更新 因为一个观察者并不知道其它观察者的存在 , 它可能对改变目标的最终代价一无所知。在目标上一个看似无害的的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外 , 如果依赖准则的定义或维护不当,常常会引起错误的更新 , 这种错误通常很难捕捉。
      简单的更新协议不提供具体细节说明目标中什么被改变了 , 这就使得上述问题更加严重。如果没有其他协议帮助观察者发现什么发生了改变,它们可能会被迫尽力减少改变。

8.实现

在php的SPL支持观察者模式,SPL 提供了 SplSubject 和 SplObserver 接口。

SplSubject 接口提供了attach()、detach()、notify() 三个方法。而 SplObserver 接口则提供了 update()方法。

SplSubject 派生类维护了一个状态,当状态发生变化时 - 比如属性变化等,就会调用 notify() 方法,这时,之前在 attach() 方法中注册的所有 SplObserver 实例的 update() 方法就会被调用。接口定义如下:

[php] view
plain
 copy

 

 

  1. <?php  
  2. /** 
  3.  * 这一模式的概念是SplSubject类维护了一个特定状态,当这个状态发生变化时,它就会调用notify()方法。 
  4.  * 调用notify()方法时,所有之前使用attach()方法注册的SplObserver实例的update方法都会被调用。 
  5.  * 
  6.  */  
  7. interface SplSubject{  
  8.       public function attach(SplObserver $observer);//注册观察者  
  9.       public function detach(SplObserver $observer);//释放观察者  
  10.       public function notify();//通知所有注册的观察者  
  11. }  
  12. interface SplObserver{  
  13.       public function update(SplSubject $subject);//观察者进行更新状态  
  14. }  

实现代码:

[php] view
plain
 copy

 

 

  1. <?php  
  2. /** 
  3.  *具体目标 
  4.  * 
  5.  */  
  6. class ConcreteSubject implements SplSubject {  
  7.   private $observers, $value;  
  8.   public function __construct() {  
  9.     $this->observers = array();  
  10.   }  
  11.   
  12.   public function attach(SplObserver $observer) { //注册观察者  
  13.     $this->observers[] = $observer;  
  14.   }  
  15.   
  16.   public function detach(SplObserver $observer) { //释放观察者  
  17.     if($idx = array_search($observer,$this->observers,true)) {  
  18.       unset($this->observers[$idx]);  
  19.     }  
  20.   }  
  21.   
  22.   public function notify() { //通知所有观察者  
  23.     foreach($this->observers as $observer) {  
  24.       $observer->update($this);  
  25.     }  
  26.   }  
  27.   
  28.   public function setValue($value) {  
  29.     $this->value = $value;  
  30.     $this->notify();  
  31.   }  
  32.   
  33.   public function getValue() {  
  34.     return $this->value;  
  35.   }  
  36.   
  37. }  
  38. /** 
  39.  * 具体观察者 
  40.  * 
  41.  */  
  42. class ConcreteObserver1 implements SplObserver {  
  43.   
  44.   public function update(SplSubject $subject) {  
  45.     echo 'ConcreteObserver1  value is ',$subject->getValue(), '<br>';  
  46.   }  
  47.   
  48. }  
  49. /** 
  50.  * 具体观察者 
  51.  * 
  52.  */  
  53. class ConcreteObserver2 implements SplObserver {  
  54.   
  55.   public function update(SplSubject $subject) {  
  56.     echo 'ConcreteObserver2 value is ', $subject->getValue(), '<br>';  
  57.   }  
  58.   
  59. }  
  60.   
  61. $subject = new ConcreteSubject();  
  62. $observer1 = new ConcreteObserver1();  
  63. $observer2 = new ConcreteObserver2();  
  64. $subject->attach($observer1);  
  65. $subject->attach($observer2);  
  66. $subject->setValue(5);  
  67. ?>  

我们扩展上面的例子,根据目标状态而更新不同的观察者:

[php] view
plain
 copy

 

 

  1. <?php    
  2. /** 
  3.  *具体目标  
  4.  *  
  5.  */    
  6.   
  7. class ConcreteSubject implements SplSubject {  
  8.     private $observers, $_state;  
  9.     public function __construct() {  
  10.         $this->observers = array();  
  11.     }  
  12.     /** 
  13.      *  注册观察者   
  14.      * 
  15.      * @param SplObserver $observer 
  16.      */  
  17.     public function attach(SplObserver $observer) {  
  18.         $this->observers[] = $observer;  
  19.     }  
  20.     /** 
  21.      *  //释放观察者   
  22.      * 
  23.      * @param SplObserver $observer 
  24.      */  
  25.     public function detach(SplObserver $observer) {  
  26.         if($idx = array_search($observer,$this->observers,true)) {  
  27.             unset($this->observers[$idx]);  
  28.         }  
  29.     }  
  30.     /** 
  31.      * 通知所有观察者   
  32.      *  
  33.      */  
  34.     public function notify() {  
  35.         /** 
  36.         * 只要状态改变,就通知观察者 
  37.         */  
  38.         foreach($this->observers as $observer) {  
  39.             if ($observer->getState() == $this->_state) {  
  40.                 $observer->update($this);  
  41.             }  
  42.         }  
  43.     }  
  44.     /** 
  45.      * 设置状态 
  46.      * 
  47.      * @param unknown_type $state 
  48.      */  
  49.     public function setState($state) {  
  50.         $this->_state = $state;  
  51.         $this->notify();  
  52.     }  
  53.   
  54.     public function getState() {  
  55.         return $this->_state;  
  56.     }  
  57.   
  58. }  
  59. /** 
  60.  * 抽象观摩者 
  61.  * 
  62.  */  
  63. abstract class bserver{  
  64.     private $_state;  
  65.   
  66.     function __construct($state) {  
  67.         $this->_state = $state;  
  68.     }  
  69.   
  70.     public function setState($state) {  
  71.         $this->_state = $state;  
  72.         $this->notify();  
  73.     }  
  74.       
  75.     public function getState() {  
  76.         return $this->_state;  
  77.     }  
  78.   
  79. }  
  80. /** 
  81.  * 具体观察者 1 
  82.  *  
  83.  */    
  84. class ConcreteObserver1 extends bserver  implements SplObserver {  
  85.   
  86.     function __construct($state) {  
  87.         parent::__construct($state);  
  88.     }  
  89.     public function update(SplSubject $subject) {  
  90.         echo 'ConcreteObserver1  state is ',$subject->getState(), '<br>';  
  91.     }  
  92.   
  93. }  
  94. /** 
  95.  * 具体观察者 2 
  96.  *  
  97.  */    
  98. class ConcreteObserver2 extends bserver   implements SplObserver {  
  99.     function __construct($state) {  
  100.         parent::__construct($state);  
  101.     }  
  102.     public function update(SplSubject $subject) {  
  103.         echo 'ConcreteObserver2 state is ', $subject->getState(), '<br>';  
  104.     }  
  105.   
  106. }  
  107. /** 
  108.  * 具体观察者 3 
  109.  *  
  110.  */    
  111. class ConcreteObserver3 extends bserver   implements SplObserver {  
  112.     function __construct($state) {  
  113.         parent::__construct($state);  
  114.     }  
  115.     public function update(SplSubject $subject) {  
  116.         echo 'ConcreteObserver3 state is ', $subject->getState(), '<br>';  
  117.     }  
  118.   
  119. }  
  120.   
  121. $subject = new ConcreteSubject();  
  122. $observer1 = new ConcreteObserver1(1);  
  123. $observer2 = new ConcreteObserver2(1);  
  124. $observer3 = new ConcreteObserver3(2);  
  125. $subject->attach($observer1);  
  126. $subject->attach($observer2);  
  127. $subject->attach($observer3);  
  128. echo 'Subject state is 1', '<br>';  
  129. $subject->setState(1);  
  130. echo 'Subject state is 2', '<br>';  
  131. $subject->setState(2);  
  132. ?>   

9.与其他相关模式

1) 终结者模式Mediator: 通过封装复杂的更新语义 , ChangeManager充当目标和观察者之间的中介者。
2) 单间模式Singleton: ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问
的。

10.总结与分析

通过Observer模式,把一对多对象之间的通知依赖关系的变得更为松散,大大地提高了程序的可维护性和可扩展性,也很好的符合了开放-封闭原则。

0
时间: 2024-09-23 18:48:31

设计模式 ( 十六 ) 观察者模式Observer(对象行为型)的相关文章

学习php设计模式 php实现观察者模式(Observer)_php技巧

一.意图 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新[GOF95] 又称为发布-订阅(Publish-Subscribe)模式.模型-视图(Model-View)模式.源-监听(Source-Listener)模式.或从属者(Dependents)模式二.观察者模式结构图   三.观察者模式中主要角色抽象主题(Subject)角色:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者.抽象主题提供了增加和删除观

设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述         在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件判断语

设计模式 ( 十五 ) 中介者模式Mediator(对象行为型)

设计模式 ( 十五 ) 中介者模式Mediator(对象行为型) 1.概述 在面向对象的软件设计与开发过程中,根据"单一职责原则",我们应该尽量将对象细化,使其只负责或呈现单一的职责,即将行为分布到各个对象中. 对于一个模块或者系统,可能由很多对象构成,而且这些对象之间可能存在相互的引用,在最坏的情况下,每一个对象都知道其他所有的对象,这无疑复杂化了对象之间的联系.虽然将一个系统分割成许多对象通常可以增强可复用性,但是对象间相互连接的激增又会降低其可复用性,大量的相互连接使得一个对象似

设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关. 例子1:银行业务办理流程 在银行办理业务时,一般都包含几个基本固定步骤: 取号排队->办理具体业务->对银行工作人员进行评分. 取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能

设计模式之观察者模式 (Observer Design Pattern)

一.什么是观察者模式 观察者定义了一种一对多的依赖关系,当一个主题(Subject)对象状态发生变化时,所有依赖它的相关对象都会得到通知并且能够自动更新自己的状态,这些依赖的对象称之为观察者(Observer)对象这类似于发布/订阅模式. 观察者模式中的主题对象,会维持着一个依赖它的观察者对象列表,当主题对象状态发生改变时,主题对象便会调用这个列表中所有观察者对象的方法. 观察者模式一般用在分布式时间处理系统,它也是流行的MVC模型的核心设计模式. 二.观察者模式中的角色 观察者模式主要涉及到三

设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)

 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述        你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就推卸给另外个一个部门(对象).至于到底谁来解决这个问题呢?政府部门就是为了可以避免屁民的请求与官员之间耦合在一起,让多个(部门)对象都有可能接收请求,将这些(部门)对象连接成一条链,并且沿着这条链传递请求,直到有(部门)对象处理它为止. 例子1:js的事件浮升机制 例子2: 2.问题

乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:webabcd 介绍 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例 有一个Message实体类,某些对象对它的操作有Insert()方法,当发生某些改变的时候,通知所有这些对象并执行Insert()方法. MessageModel using

设计模式:观察者模式(observer)

设计模式:观察者模式(observer) 这种设计模式大量的使用,简单的说就是观察者通过被观察者来获得外界某种事物的状态 Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步. 如下图: image.png 被观察者(concreteSubject):其中必然包含了一个观察者的列表,用于状态发生变化的时候通过链表进行通知每个观察者做出相应的变化 观察者(ConcreteObserver):其中必然包含各种应对外界状态变化的方法,以供被观察者调用 图中

JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片

JAVA之旅(二十六)--装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片 一.装饰设计模式 其实我们自定义readLine就是一种装饰模式 当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,并且提供加强功能,那么自定义的该类就称为装饰类 package com.lgl.hellojava; public class HelloJJAVA { public static void main(S