观察者,好像很多科幻作品中都会出现这个角色。比如我很喜欢一部美剧《危机边缘》。在这一集中,观察者不断穿越时空,记录各种人或事。但是,设计模式中的观察者并不是仅仅站在一旁观望,这里的观察者是为了响应主体的状态变化而做出相应的动作。Gof类图及解释GoF定义:定义对象之间一对多的依赖关系。当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。GoF类图代码实现interfaceObserver{publicfunctionupdate(Subject$subject):void;}Observer的抽象接口,没什么好说的,就是让你具体实现一个Update类ConcreteObserverimplementsObserver{private$observerState='';函数更新(主题$subject):void{$this->observerState=$subject->getState();echo'执行观察者操作!当前状态:'。$this->observerState;}}具体观察者实现了update()方法,这里我们得到了Subject类,所以我们可以得到状态类Subject{private$observers=[];私人$stateNow='';publicfunctionattach(Observer$observer):void{array_push($this->observers,$observer);}publicfunctiondetach(Observer$observer):void{$position=0;foreach($this->observersas$ob){if($ob==$observer){array_splice($this->observers,($position),1);}}++$位置;}}公共函数通知():void{foreach($this->observersas$ob){$ob->update($this);}}}Subject父类维护了一个观察者数组,然后有方法对这个数组进行增删改查,目的是方便管理所有的观察者classConcreteSubjectextendsSubject{publicfunctionsetState($state){$this->stateNow=$state;$this->通知();}publicfunctiongetState(){return$this->stateNow;}}Subject的实现类只是更新状态。当状态发生变化时,调用观察者的遍历方法执行所有的观察。update()操作观察者其实是在做一个更新(update),Subject可以批量执行观察者。请注意,我们不需要修改目标类中的任何代码,我们只需要从外部添加它,这样就让目标和观察者解耦,互不关心观察者可以记录状态目标,或不。比如我们发完一条短信后,更新数据库或者插入操作。只有短信接口发送成功后,我们才能修改短信数据的状态,不一定是完整的。需要将目标的发送状态传递给观察者。当一个班级发生变化时,不知道有多少其他班级会受到影响。这时候,观察者就非常有用了。在观察者模式中仍然存在耦合,即有一个观察者对象列表。如果观察者没有实现update()方法,那么就会出现问题。说说我们的手机厂吧。发布什么功能(状态更新),他们会相应发布同样的功能(更新),他们在我的基础上做了更多的事情。美其名曰:微创新!你说生气不生气嗯,我也派了一批市场调研员(观察员)帮我观察一下别人手机有什么功能(状态更新),然后我们也复制到这里,做一些微创新,这样大家才能进步一起。!!完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/06.observer/source/observer.php示例这次我们先从订单开始,不过还有一个发送短信的问题。当有人在一般电商平台下单时,需要做的事情很多,比如修改库存,发送短信或推送告诉商家有人下单了,告诉买家下单成功,付款成功。总之,一个事件的发生会导致各种事件的产生。其实这里介绍另一种非常知名的模式订阅发布模式。这种模式可以说是观察者的升级模式。本系列文章不再赘述,大家可以去看看Laravel中发布订阅和事件监听的内容。订单销售类图完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/06.observer/source/order-observer.phpinterfaceObserver{publicfunctionupdate($obj);}classMessageimplementsObserver{//....functionupdate($obj){echo'发送新订单消息('.$obj->mobile.')通知商家!';}//....}classGoodsimplementsObserver{//....publicfunctionupdate($obj){echo'修改商品'.$obj->商品编号。'存货!';}//....}classOrder{private$observers=[];publicfunctionattach($ob){$this->observers[]=$ob;}publicfunctiondetach($ob){$position=0;foreach($this->observersas$ob){if($ob==$observer){array_splice($this->observers,($position),1);}}++$位置;}}publicfunctionnotify($obj){foreach($this->observersas$ob){$ob->update($obj);}}普blicfunctionsale(){//商品售出//....$obj=newstdClass();$obj->mobile='13888888888';$obj->goodsId='Order11111111';$this->通知($obj);}}$message=newMessage();$goods=newGoods();$order=newOrder();$order->attach($message);$order->attach($goods);//订单被卖了!!$订单->销售();说明我们没有完全遵守GoF类图。GoF虽然是圣经,但不是我们必须完全遵守的。我们可以针对具体的业务情况进行适当的裁剪,使用订单状态通过sale()方法改变后,直接调用notify方法调用观察者。发送短信和发送推送消息可以由观察者一一拆解实现。这些观察者不一定只有这个方法,只要实现了一个通用的接口即可。商品库存和消息发送其实是两个完全不相关的类,但它们只需要实现相同的接口即可。PHP的SPL扩展为我们准备了一套观察者接口。大家可以试试试试看,使用原生支持的观察者模式可以省很多事!完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/06.observer/source/spl_observer.php下期的高亮循环是编程语言的高亮,因为这个能力可以让编程语言使之成为软件,可以代替人做很多重复性的劳动。说到这里,有人马上就会想到,难道是我们下次要讲的迭代器模式吗?让我们等着看!============各媒体平台均可搜索【硬核项目经理】
