初学设计模式之观察者模式

                                                                                                         @[TOC](观察者模式)

观察者模式定义

观察者模式又称发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象,当主题对象发生变化时会通知所有观察者对象,使他们能够更新自己

从故事开始

老高:今天摸鱼看股票又被老板抓住了,半天工资没了
老摸:你可以贿赂一下前台小美,等老板回公司的时候就给你发消息,你就可以及时切换到工作面板了
老高:好主意,我这就去买奶茶

用代码描述故事

前台秘书类 (监听:用来监听老板有没有回来)

class Secretary
{
    public $observers = [];
    public $action = '';

    // 添加
    public function attach(StockObserver $observer)
    {
        $this->observers = array_merge($this->observers, $observer);
        return $this;
    }

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

    public function setAction($name)
    {
        return $this->action = $name;
    }
}

看股票的同事 (观察者:老板来了改变自己的状态)

class StockObserver
{
    public $name = '';
    public $sub;

    public function __construct($name,Secretary9 $sub)
    {
        $sub->setAction($name);
    }
    
    public function update()
    {
        $action = $this->sub->action;
        return $this->name + "关闭股票继续工作!"+$action;
    }
}

控制器中使用观察者模式 (小美如何向同事发消息)

class Controller
{
    public function run()
    {
        $tongzhi = new Secretary();
        $laogao = new StockObserver("老高", $tongzhi);
        $laomo = new StockObserver("老摸", $tongzhi);

        $tongzhi->attach($laogao);
        $tongzhi->attach($laomo);

        $tongzhi->action = "老板来了";

        return $tongzhi->notify();
    }
}

解耦

故事讲完了,但是代码也实现了,但是问题也出现了,
问题:

  1. 如果有的同事在看直播而不是股票呢,那小美岂不是通知错
  2. 如果小美休假小帅值班,那通知者就是小帅而不是小美
    对于这种情况最简单粗暴的方式就是加一个前台小帅秘书类 和一个看直播的同事类
    但是这样代码重复就很多了,所以这段代码需要解耦
抽离前台秘书类

前台秘书类接口

interface Subject
{
    public function attach(Observer $observer);
    public function notify();
    public function setAction($name);
}

前台秘书小美类

class XiaoMei implements Subject
{
    public $observers = [];
    public $action = '';

    // 添加
    public function attach(Observer $observer)
    {
        $this->observers = array_merge($this->observers, $observer);
        return $this;
    }

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

    public function setAction($name)
    {
        return $this->action = $name;
    }
}

前台秘书小帅类

与小美的代码类似此处略
抽离观察者

摸鱼同事接口类

abstract class Observer
{
    public $name = '';
    public $sub;

    public function __construct($name,Subject $sub)
    {
        $sub->setAction($name);
    }

    abstract public function update();
}

看股票同事接口类

class StockObserver extends Observer
{
    public function update()
    {
        $action = $this->sub->action;
        return $this->name + "关闭股票继续工作!"+$action;
    }
}

看直播同事接口类

class LiveObserver extends Observer
{
    public function update()
    {
        $action = $this->sub->action;
        return $this->name + "关闭直播继续工作!"+$action;
    }
}

控制器中使用观察者模式

class Controller
{
    public function run()
    {
        $tongzhi = new XiaoMei();

        $laogao = new StockObserver("老高", $tongzhi);
        $laomo = new NBAObserver("老摸", $tongzhi);

        $tongzhi->attach($laogao);
        $tongzhi->attach($laomo);

        $tongzhi->action = "老板来了~~";
        return $tongzhi->notify();
    }
}

总结

观察者模式是将一个系统分割成一系列相互写作的类,有一个很不好的副作用就是需要维护相关对象的一致性。一个主题subject(秘书)可以有任意个观察者observer(同事),一但主题subject(秘书)发生改变,所有的观察者observer(同事)都会得到通知

什么时候使用呢?

当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象待改变的情况下,这个时候应该考虑使用观察者模式

有什么优势呢

观察者模式所做的工作其实就是在解耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化

观察者模式的不足
  1. 抽象通知者Subject(前台秘书类接口)还是依赖抽象观察者Observer(摸鱼同事接口类),万一没有抽象观察者这样的接口,我这个功能就完不成了,
  2. 另外每一个功能并不一定是更新(update)的时候才会使用,或者隐藏(hidden)的时候也会使用,更新和隐藏者两个是不同名的方法
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值