观察者模式

定义

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

又称为发布-订阅模式,监听模式

主要角色

  • 抽象Subject:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者。抽象主题提供了增加和删除观察者对象的接口。
  • 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在观察的主题发生改变时更新自己。
  • 具体主题(ConcreteSubject)角色:存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
  • 具体观察者(ConcretedObserver)角色:存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。

适用性

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。

一句话理解

将需要被监听的类,统一放到一个集合中,当需要统一操作的时候,遍历循环这个集合,通知各个对象去做操作.

实例

不使用SplObserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php
/**
* Created by PhpStorm.
* User: Livfer
* Desc:
* Date: 2019/9/18
* Time: 16:52
*/

/**
* 抽象观察者角色
* Interface Observer
*/
interface Observer
{
public function update();
}

/**
* 抽象主题角色
* Interface Subject
*/
interface Subject
{
/**
* 增加观察者对象
* @param Observer $observer
* @return mixed
*/
public function attach(Observer $observer);

/**
* 移除观察者对象
* @param Observer $observer
* @return mixed
*/
public function detach(Observer $observer);

/**
* 通知注册过的观察者对象
* @return mixed
*/
public function notify();
}

/**
* 具体主题角色
* Class ConcreteSubject
*/
class ConcreteSubject implements Subject
{
protected $observes = [];

/**
* 增加观察者对象
* @param Observer $observer
* @return mixed
*/
public function attach(Observer $observer)
{
// TODO: Implement attach() method.
return array_push($this->observes, $observer);
}

/**
* 移除观察者对象
* @param Observer $observer
* @return mixed
*/
public function detach(Observer $observer)
{
// TODO: Implement detach() method.
$index = array_search($observer, $this->observes);
if ($index === false || !isset($this->observes[$index])) {
return false;
}
unset($this->observes[$index]);
return true;
}

/**
* 通知注册过的观察者对象
* @return mixed
*/
public function notify()
{
// TODO: Implement notify() method.
if (!is_array($this->observes)) return false;
foreach ($this->observes as $observe) {
$observe->update();
}

return true;
}
}

class ConcreteObserve implements Observer
{

private $name;

public function __construct($name)
{
$this->name = $name;
}
public function update()
{
// TODO: Implement update() method.
echo $this->name.'更新';
}
}

$subjectOne = new ConcreteSubject();
//添加一个观察者
$observeOne = new ConcreteObserve('Mac');
$observeTwo = new ConcreteObserve('Windows');
$subjectOne->attach($observeOne);
$subjectOne->attach($observeTwo);
//通知更新
$subjectOne->notify();

使用SplObserver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php
/**
* Created by PhpStorm.
* User: Livfer
* Desc:
* Date: 2019/9/18
* Time: 17:11
*/

class DefaultSplObServer implements SplObserver
{

/**
* Receive update from subject
* @link https://php.net/manual/en/splobserver.update.php
* @param SplSubject $subject <p>
* The <b>SplSubject</b> notifying the observer of an update.
* </p>
* @return void
* @since 5.1.0
*/
public function update(SplSubject $subject)
{
// TODO: Implement update() method.
}
}

class DefaultSplSubject implements SplSubject
{

/**
* Attach an SplObserver
* @link https://php.net/manual/en/splsubject.attach.php
* @param SplObserver $observer <p>
* The <b>SplObserver</b> to attach.
* </p>
* @return void
* @since 5.1.0
*/
public function attach(SplObserver $observer)
{
// TODO: Implement attach() method.
}

/**
* Detach an observer
* @link https://php.net/manual/en/splsubject.detach.php
* @param SplObserver $observer <p>
* The <b>SplObserver</b> to detach.
* </p>
* @return void
* @since 5.1.0
*/
public function detach(SplObserver $observer)
{
// TODO: Implement detach() method.
}

/**
* Notify an observer
* @link https://php.net/manual/en/splsubject.notify.php
* @return void
* @since 5.1.0
*/
public function notify()
{
// TODO: Implement notify() method.
}
}

参考

[设计模式详解以及PHP实现][http://yansu.org/2014/04/19/design-patterns-of-php.html]