今天要说的是观察者模式,这是一种很常见的模式,很多事件都是基于这种模式分发的。这里我就从一个话题说起这个模式的使用。有这样一个问题:某市报社开办,市民订阅报纸。尝试使用观察者模式来解决这个问题。在使用观察者模式之前,先说一下常用的处理方式。类发布者{public$title='';公共函数__construct($title){$this->title=$title;}publicfunctionpush(){echo"【{$this->title}】发布新闻".PHP_EOL;}}classPeople{public$name='';公共函数__construct($name){$this->name=$name;}publicfunctionpull(Publisher$publisher){echo"【{$this->name}】收到【{$publisher->title}】发布的消息"。PHP_EOL;}}/*初始化用户*/$peoples=[];for($i=1;$i<=5;$i++){$peoples[]=newPeople("User{$i}");}/*报纸使用push方式发布新闻*/$publisher=newPublisher("Newspaper1");$publisher->push();/*所有订阅的公民使用pull方法接收报纸对象*/foreach($peoplesas$people){$people->pull($publisher);}publisher每次使用push方法,都需要循环$peoples进行通知,当然这里可以封装一个函数,每次调用都可以。下面是运行截图:上面的代码运行肯定没有问题,而且也很容易理解。只要运行push方法,就会循环调用pull方法。但是每次都打电话很麻烦。有更好的改进吗?看看下面的代码:classPublisher{public$title='';私人$peoples=[];公共函数__construct($title,$peoples){$this->title=$title;$this->peoples=$peoples;}publicfunctionpush(){echo"【{$this->title}】发布新闻".PHP_EOL;//消息发布后,通知所有订阅用户foreach($this->peoplesas$people){//注意这里有$this$people->pull($this);}}}//原来的People类不变,此处省略$peoples=[];for($i=1;$i<=5;$i++){$peoples[]=newPeople("User{$i}");}//创建$publisher时,直接将$peoples发送给报纸$publisher=newPublisher("报纸1",$peoples);$publisher->push();这里可以看到循环被移到了Publisher类中,每次执行push方法,所有的people对象都能收到消息。但是这里$peoples是通过构造函数传入的,能不能分开呢?让我们重写下面的代码:classPublisher{public$title='';私人$peoples=[];公共函数__construct($title){$this->title=$title;}publicfunctionaddPeople(People$people){$this->peoples[]=$people;}publicfunctionpush(){echo"[{$this->title}]发布新闻".PHP_EOL;foreach($this->peoplesas$people){$people->pull($this);}}}}//Client$publisher=newPublisher("Newspaper1");对于($i=1;$i<=5;$i++){$publisher->addPeople(newPeople("User{$i}"));}$publisher->push();改成这样后使用起来很方便,思路也很清晰。以上就是观察者模式的原型,接下来就是抽象了...interfaceIObserver{publicfunctionupdate(Publisher$publisher);}classPublisher{public$title='';私人$observers=[];公共函数__construct($title){$this->title=$title;}publicfunctionattach(IObserver$observer){$this->observers[]=$observer;}publicfunctionpush(){echo"【{$this->title}】发布新闻".PHP_EOL;foreach($this->observersas$observer){$observer->更新($this);}}}classPeople实现IObserver{public$name='';公共函数__construct($name){$this->name=$name;}publicfunctionupdate(Publisher$publisher){echo"【{$this->name}】收到了【{$publisher->title}】发布的消息".PHP_EOL;}}$publisher=newPublisher("Newspaper1");for($i=1;$i<=5;$i++){$publisher->attach(newPeople("User{$i}"));}$publisher->push();以上是一个比较标准的观察者模式结构,需要在IObserve中说明r接口中定义的update方法参数可以根据场景需要修改。另外要说的是,在Publisher类中,可以创建一个detach方法用于取消订阅。这样,整个$peoples的管理就比较完整了。其实有时候觉得学习设计模式不要太死板,只要思路对了,想写什么就写什么。
