PHP设计模式 三
3 观察者模式
使用场景:一个操作结束后会需要后续操作。
被观察者暴露并抛出对应事件,通过事件分发器触发观察者。
观察者监听事件,对应事件相应并进行操作。
用户模块 服务 登录处理 事件 登录事件 短信模块 监听 登录 common interface 事件 事件监听 class 事件分发器
事件interface,要求必须定义事件名和数据。
事件监听interface,要求必须处理对用的事件,检验事件名并执行对应方法。
事件分发器注册监听并在用户模块服务类中调用。
模块下的事件实现事件interface,模块下的监听实现事件监听interface。
执行顺序
controller->logic->注册监听->模块/服务模块/服务->模块/事件->事件分发->模块/监听
假设场景
用户登录,记录上次登录时间ip 本次登录时间ip,发送短信告知。
被观察者为登录操作;观察者为短信发送模块。
common
事件interface
interfaceEvent{publicfunctiongetName(): string;publicfunctiongetData();}
事件监听interface
interfaceListener{publicfunctionhandle(Event $event): void;publicfunctiongetEventName(): string;}
事件分发器
classEventDispatcher{privatearray $listeners = [];//添加监听publicfunctionaddListener(Listener $listener): void{ $eventName = $listener->getEventName();$this->listeners[$eventName][] = $listener; }//事件分发publicfunctiondispatch(Event $event): void{ $eventName = $event->getName();if (isset($this->listeners[$eventName])) {foreach ($this->listeners[$eventName] as $listener) { $listener->handle($event); } } }}
基础监听类
可以没有 起到记录日志作用
abstractclassBaseListenerimplementsListener{protectedfunctionlog(string $message): void{echo"[{$this->getEventName()}] " . $message . "\n"; }}
被观察者
用户模块登录事件
classLoginEventimplementsEvent{private string $name = 'user.login';privatearray $data;publicfunction__construct(array $data){$this->data = $data; }//设置事件名字publicfunctiongetName(): string{return$this->name; }//获取事件数据publicfunctiongetData(){return$this->data; }}
用户模块服务
classUserService{private EventDispatcher $dispatcher;publicfunction__construct(){$this->dispatcher = new EventDispatcher(); }//登录操作 publicfunctionlogin(string $phone, string $pwd): void{// to do 登录逻辑 根据$phone和$pwd获取用户信息 $userinfo = []; $user_id = $userinfo->id; $login_time = date('Y-m-d H:i:s'); $isSafe = false;if(empty($isSafe)){ $safe_msg ="上次登录时间/IP,本次登录时间/IP"; $userData = ['user_id'=>$userid,'safe_msg'=>$safe_msg,'phone' => $phone, ];// 触发事件 可改为异步操作$this->dispatcher->dispatch(new LoginEvent($userData)); }return$this->formatLoginInfo($userinfo); }//格式化登录后信息publicfunctionformatLoginInfo($userinfo){//to do 格式化用户信息 $userinfo_use = [];return $userinfo_use; }//获取事件分发类publicfunctiongetDispatcher(): EventDispatcher{return$this->dispatcher; }}
观察者
短信模块 用户登录监听类
classLoginSmsListenerextendsBaseListener{//获取对应事件名字publicfunctiongetEventName(): string{return'user.login'; }//执行对应事件方法publicfunctionhandle(Event $event): void{ $data = $event->getData();$this->log("发送短信到 {$this->phone}");//to do 发送短信//发送$data[safe_msg]到$data[phone]; }}
调用
controller层
classUserextendsController{publicfunctionlogin(){//获取请求参数 $params = (new $Request())->getParams(); $phone = $params['phone']; $pwd = $params['pwd']; $userLoginc = new UserLogic(); $result = $userLoginc->login($phone,$pwd);if(1==empty($result[0])){ $returnData =['code'=>200,'msg'=>$result[1],'data'=>$result[2]]; }else{ $returnData =['code'=>$result[0],'msg'=>$result[1],'data'=>[]]; }//返回数据return json_encode($returnData); }}
logic层
publicfunctionUserLogic{publicfunctionlogin($phone,$pwd){ $userServer = new UserService();try{//注册监听 $dispatcher = $userService->getDispatcher(); $dispatcher->addListener(new LoginSmsListener());//执行登录操作 $userinfo = $userService->logic($phone, $pwd);return [1,"操作成功",$userinfo]; }cache(\Exception $e){return [$e->getCode(),$e->getMessage()]; } }}