观察者模式的总结

什么是观察者模式

观察者模式用于实现对对象进行观察:一旦主体对象状态发生改变,与之关联的观察者对象会收到通知,并进行相应操作。

举个例子说明:
假设一个这样的情景,当公司有一个新员工入职了,入职的当天,HR需要为他办理入职手续,网管需要给他配好电脑和办公用品,部门主管需要带他熟悉部门。传统的编程方式,就是在员工入职这个事件发生的代码之后直接加入处理逻辑,当后续我们需要增加处理逻辑时(比如员工入职后增加培训),代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要改变事件主题的代码。运用观察者模式,将员工的入职作为事件,其他的处理逻辑都做为观察者的操作,那么,当以后需要再增加更多的逻辑时,新增逻辑代码就会很方便。具体代码实现如下。

代码实现

首先定义一个观察者接口,所有的观察者都实现这个接口(为什么要定义成接口呢?因为每一个观察者的具体行为需要具体去实现,用接口定义一个统一的方法,具体的实现交给观察者去实现)

interface observer
{
    public function update();
}

再定义一个事件生成器的抽象类,用来使继承它的事件都具有通知观察者的能力。

abstract class EventGenerator
{
    private $observers = [];

    //定义一个添加观察者的方法
    public function addOberver(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    //定义一个通知观察者的方法
    public function notify()
    {
        foreach($this->observers as $observer)
        {
            $observer->update();
        }
    }

}

然后再来定义事件类

class event extends EventGenerator
{
    //定义一个触发观察者的方法
    public funtion trigger()
    {
        echo "Event <br/>";

        //开始通知观察者
        $this->notify();
    }   
}

开始使用

$event = new event();
$event->trigger();

这个时候,当我们要在事件发生的时候增加别的操作,只需要新增观察者就可以了

新增一个观察者

class Observer1 implements Observer
{
    public function update()
    {
        echo "操作1<br/>";    
    }

}

然后使用的时候就是

$event = new event();
// 增加观察者
$event->addObserver(new Observer1);
$event->trigger();

如果需要在事件发生后再增加操作,只需再新增相应的观察者即可。

应用观察者模式的好处

观察者模式解除了主体和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。降低对象之间的耦合度以达到解耦的目的,符合"开闭原则"的要求。

利用 SPL 实现观察者模式

PHP 通过内置的 SPL 扩展提供了对观察者模式的原生支持,其中的观察者由 3 个元素组成 : SplObserver 接口、 SplSubject 接口和 SplObjectStorage 工具类。下面是利用 SPL 实现观察者模式的代码。SPL 的地址见这里


class MyObserver1 implements SplObserver {
    public function update(SplSubject $subject) {
        echo __CLASS__ . ' - ' . $subject->getName();
    }
}

class MyObserver2 implements SplObserver {
    public function update(SplSubject $subject) {
        echo __CLASS__ . ' - ' . $subject->getName();
    }
}

class MySubject implements SplSubject {
    private $observers;
    private $name;

    public function __construct($name) {
        $this->observers = new SplObjectStorage();
        $this->name = $name;
    }

    public function attach(SplObserver $observer) {
        $this->observers->attach($observer);
    }

    public function detach(SplObserver $observer) {
        $this->observers->detach($observer);
    }

    public function notify() {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    public function getName() {
        return $this->name;
    }
}

$observer1 = new MyObserver1();
$observer2 = new MyObserver2();

$subject = new MySubject("test");

$subject->attach($observer1);
$subject->attach($observer2);
$subject->notify();

/* 
输出:

MyObserver1 - test
MyObserver2 - test
*/

$subject->detach($observer2);
$subject->notify();

/* 
输出:

MyObserver1 - test
*/
本作品采用《CC 协议》,转载必须注明作者和本文链接
You can not connect the dots looking forward, you can only connect them looking backwards.
本帖由系统于 6年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 8

每次都能看明白.但是到了用的时候根本想不起来....时间一长还有可能忘记了...这怎么破.

6年前 评论

@736713830 光看明白是不够的,一方面需要去实际应用,另一方面,你也可以试着自己总结起来,这样会有更加深入的理解

6年前 评论

@Jeffrey00 嗯 感谢.已经动手理解了一遍.

6年前 评论

@Jeffrey00 当才华撑不起野心时,就静下来学习。 我喜欢这句话.

6年前 评论
godruoyi

我最近也在瞅设计模式,共勉!! :+1:

6年前 评论
wanghan

言简意赅,全是精华!赞!

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!