`

观察者模式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() 方法就会被调用。接口定义如下:

 

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

 

 

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

  public function attach(SplObserver $observer) { //注册观察者
    $this->observers[] = $observer;
  }

  public function detach(SplObserver $observer) { //释放观察者
    if($idx = array_search($observer,$this->observers,true)) {
      unset($this->observers[$idx]);
    }
  }

  public function notify() { //通知所有观察者
    foreach($this->observers as $observer) {
      $observer->update($this);
    }
  }

  public function setValue($value) {
    $this->value = $value;
    $this->notify();
  }

  public function getValue() {
    return $this->value;
  }

}
/**
 * 具体观察者
 *
 */
class ConcreteObserver1 implements SplObserver {

  public function update(SplSubject $subject) {
    echo 'ConcreteObserver1  value is ',$subject->getValue(), '<br>';
  }

}
/**
 * 具体观察者
 *
 */
class ConcreteObserver2 implements SplObserver {

  public function update(SplSubject $subject) {
    echo 'ConcreteObserver2 value is ', $subject->getValue(), '<br>';
  }

}

$subject = new ConcreteSubject();
$observer1 = new ConcreteObserver1();
$observer2 = new ConcreteObserver2();
$subject->attach($observer1);
$subject->attach($observer2);
$subject->setValue(5);
?>

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

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

class ConcreteSubject implements SplSubject {
	private $observers, $_state;
	public function __construct() {
		$this->observers = array();
	}
	/**
     *  注册观察者  
     *
     * @param SplObserver $observer
     */
	public function attach(SplObserver $observer) {
		$this->observers[] = $observer;
	}
	/**
     *  //释放观察者  
     *
     * @param SplObserver $observer
     */
	public function detach(SplObserver $observer) {
		if($idx = array_search($observer,$this->observers,true)) {
			unset($this->observers[$idx]);
		}
	}
	/**
     * 通知所有观察者  
     * 
     */
	public function notify() {
		/**
  	 	* 只要状态改变,就通知观察者
  	 	*/
		foreach($this->observers as $observer) {
			if ($observer->getState() == $this->_state) {
				$observer->update($this);
			}
		}
	}
	/**
     * 设置状态
     *
     * @param unknown_type $state
     */
	public function setState($state) {
		$this->_state = $state;
		$this->notify();
	}

	public function getState() {
		return $this->_state;
	}

}
/**
 * 抽象观摩者
 *
 */
abstract class bserver{
	private $_state;

	function __construct($state) {
		$this->_state = $state;
	}

	public function setState($state) {
		$this->_state = $state;
		$this->notify();
	}
	
	public function getState() {
		return $this->_state;
	}

}
/**
 * 具体观察者 1
 * 
 */  
class ConcreteObserver1 extends bserver  implements SplObserver {

	function __construct($state) {
		parent::__construct($state);
	}
	public function update(SplSubject $subject) {
		echo 'ConcreteObserver1  state is ',$subject->getState(), '<br>';
	}

}
/**
 * 具体观察者 2
 * 
 */  
class ConcreteObserver2 extends bserver   implements SplObserver {
	function __construct($state) {
		parent::__construct($state);
	}
	public function update(SplSubject $subject) {
		echo 'ConcreteObserver2 state is ', $subject->getState(), '<br>';
	}

}
/**
 * 具体观察者 3
 * 
 */  
class ConcreteObserver3 extends bserver   implements SplObserver {
	function __construct($state) {
		parent::__construct($state);
	}
	public function update(SplSubject $subject) {
		echo 'ConcreteObserver3 state is ', $subject->getState(), '<br>';
	}

}

$subject = new ConcreteSubject();
$observer1 = new ConcreteObserver1(1);
$observer2 = new ConcreteObserver2(1);
$observer3 = new ConcreteObserver3(2);
$subject->attach($observer1);
$subject->attach($observer2);
$subject->attach($observer3);
echo 'Subject state is 1', '<br>';
$subject->setState(1);
echo 'Subject state is 2', '<br>';
$subject->setState(2);
?> 

9.与其他相关模式

 

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

 

10.总结与分析

 

 

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

相关推荐

    C#面向对象设计模式纵横谈(19):(行为型模式) Observer 观察者模式 (Level 300)

    C#面向对象设计模式纵横谈(19):(行为型模式) Observer 观察者模式 (Level 300)

    (行为型模式) Observer 观察者模式

    C#面向对象设计模式 (行为型模式) Observer 观察者模式 视频讲座下载

    观察者模式(Observer)原理图

    观察者模式(Observer Pattern)是一种对象行为型设计模式,它定义了对象之间的一对多依赖关系。 当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现分布式事件处理系统...

    Java 观察者模式的浅析

    Java 观察者模式的浅析 ... 观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。

    设计模式 观察者 发布/订阅 Observer

    Observer (观察者模式) 又叫做发布/订阅(Publish/Subscribe)模式。 当一个对象的改变同时会影响其他对象的行为的时候,可以使用此设计模式。 l 主题对象 :一个需要被关注的主题对象,这个主题对象改变会影响...

    观察者模式

    简单地说,观察者模式定义... 观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。

    c++设计模式-行为型模式-观察者模式

    c++设计模式-行为型模式-观察者模式;qt工程;c++简单源码; 观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式...

    C#设计模式(17)——观察者模式(Observer Pattern).pdf

    从生活中的例子可以看出,只要对订阅号... 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的行为。

    设计模式可复用面向对象软件的基础.zip

    5.7 OBSERVER(观察者)—对象行为型 模式 194 5.8 STATE(状态)—对象行为型模式 201 5.9 STRATEGY(策略)—对象行为型 模式 208 5.10 TEMPLATE METHOD(模板方法) —类行为型模式 214 5.11 VISITOR(访问者)—...

    C#面向对象设计模式纵横谈(视频与源码)

    C#面向对象设计模式纵横谈(19):(行为型模式) Observer 观察者模式 C#面向对象设计模式纵横谈(20):(行为型模式) Chain Of Responsibility 职责链模式 C#面向对象设计模式纵横谈(21):(行为型模式) Memento 备忘...

    JavaScript设计模式之观察者模式与发布订阅模式详解

    本文实例讲述了JavaScript设计模式之观察者模式与发布订阅模式。...观察者模式属于行为型模式。在观察模式中共存在两个角色观察者(Observer)与被观察者(Subject),然而观察者模式在软件设计中是一个

    设计模式_观察者模式.zip

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。 观察者模式demo java

    设计模式之11个行为型模式

    行为型简介职责链模式(ChainofResponsibility)命令模式(Command)解释器模式(Interpreter)迭代器模式(Iterator)中介者模式(Mediator)备忘录模式(Memento)观察者模式(Observer)状态模式(State)策略模式(Strategy)模板...

    设计模式--可复用面向对象软件的基础

    5.7 OBSERVER(观察者)——对象行为型模式 5.8 STATE(状态)——对象行为型模式 5.9 STRATEGY(策略)——对象行为型模式 5.10 TEMPLATE METHOD(模板方法)——类行为型模式 5.11 VISITOR(访问者)——对象行为...

    设计模式可复用面向对象软件的基础.

    5.7 OBSERVER(观察者)—对象行为型 模式 194 5.8 STATE(状态)—对象行为型模式 201 5.9 STRATEGY(策略)—对象行为型 模式 208 5.10 TEMPLATE METHOD(模板方法) —类行为型模式 214 5.11 VISITOR(访问者)—...

    设计模式:可复用面向对象软件的基础

    5.7 OBSERVER(观察者)—对象行为型 模式 194 5.8 STATE(状态)—对象行为型模式 201 5.9 STRATEGY(策略)—对象行为型 模式 208 5.10 TEMPLATE METHOD(模板方法) —类行为型模式 214 5.11 VISITOR(访问者)—...

Global site tag (gtag.js) - Google Analytics