Home > Article > Backend Development > PHP design pattern Observer pattern
Concept
The observer pattern is a behavioral pattern that defines a one-to-many dependency relationship between objects, so that when the state of an object changes, all objects that depend on it are notified and automatically refreshed.
When the state of an object changes, it will affect the changes of several other objects. At this time, the observer mode can be used.
The observer pattern complies with the interface isolation principle and achieves loose coupling between objects.
Alias
Publish-Subscribe> Pattern
Model-View
Source-Listener> Pattern
Slave Pattern
Role
Abstract Subject (Subject): It keeps references to all observer objects in a collection, and each subject can have any number of observers. The abstract theme provides an interface to add and remove observer objects.
Concrete Subject (ConcreteSubject): Store the relevant status in a specific observer object; when the internal status of the specific subject changes, a notification is sent to all registered observers.
Abstract Observer (Observer): Define an interface for all concrete observers and update themselves when notified by the topic.
Concrete Observer: Implement the update interface required by the abstract observer role in order to coordinate its own state with the subject state.
UML diagram
Code
Sample code
The SplSubject and SqlOberver interfaces have been provided in PHP SPL. The source code is as follows:
/** * The <b>SplSubject</b> interface is used alongside * <b>SplObserver</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splsubject.php */ interface SplSubject { /** * Attach an SplObserver * @link http://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); /** * Detach an observer * @link http://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); /** * Notify an observer * @link http://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify (); } /** * The <b>SplObserver</b> interface is used alongside * <b>SplSubject</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splobserver.php */ interface SplObserver { /** * Receive update from subject * @link http://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); }
Now we write our own code based on these two spl interfaces:
<?php header('Content-type:text/html;charset=utf-8'); /** * Class Subject 主题 */ class Subject implements SplSubject { private $_observers = []; /** * 实现添加观察者方法 * * @param SplObserver $observer */ public function attach(SplObserver $observer) { if (!in_array($observer, $this->_observers)) { $this->_observers[] = $observer; } } /** * 实现移除观察者方法 * * @param SplObserver $observer */ public function detach(SplObserver $observer) { if (false !== ($index = array_search($observer, $this->_observers))) { unset($this->_observers[$index]); } } /** * 实现提示信息方法 */ public function notify() { foreach ($this->_observers as $observer) { $observer->update($this); } } /** * 设置数量 * * @param $count */ public function setCount($count) { echo "数据量加" . $count . '<br>'; } /** * 设置积分 * * @param $integral */ public function setIntegral($integral) { echo "积分量加" . $integral . '<br>'; } } /** * Class Observer1 观察者一 */ class Observer1 implements SplObserver { public function update(SplSubject $subject) { $subject->setCount(10); } } /** * Class Observer2 观察者二 */ class Observer2 implements SplObserver { public function update(SplSubject $subject) { $subject->setIntegral(10); } } /** * Class Client 客户端 */ class Client { /** * 测试方法 */ public static function test() { // 初始化主题 $subject = new Subject(); // 初始化观察者一 $observer1 = new Observer1(); // 初始化观察者二 $observer2 = new Observer2(); // 添加观察者一 $subject->attach($observer1); // 添加观察者二 $subject->attach($observer2); // 消息提示 $subject->notify();//输出:数据量加1 积分量加10 // 移除观察者一 $subject->detach($observer1); // 消息提示 $subject->notify();//输出:数据量加1 积分量加10 积分量加10 } } // 执行测试 Client::test();
Running results
数据量加10 积分量加10 积分量加10
Advantages and Disadvantages
Advantages
The coupling between the observer and the subject is small;
Supports broadcast communication;
Disadvantages
Since the observer does not know the existence of other observers, it may No idea of the ultimate cost of changing goals. This may cause unexpected updates.
Applicable scenarios
When an abstract model has two aspects, one of them depends on the other.
When changing one object requires changing other objects at the same time, you don’t know how many objects need to be changed.
When an object must notify other objects, it cannot assume who the other objects are. In other words, you don't want these objects to be tightly coupled.