php设计模式(1)-- 观察者模式 -- spl标准写法
php设计模式(2)-- 观察者模式 -- 用trait来改进的写法
php设计模式(3)-- 责任链(职责链)模式
php设计模式(4)-- 装饰器模式
本文讲观察者模式。
部分代码来源:
https://www.ibm.com/developerworks/cn/opensource/os-cn-observerspl/
概述
个人的心得体会:最重要的一点,目标对象,给观察者对象发通知时,不需要对方的返回值,仅仅把通知下发就完事。
这是最重要的。如果需要返回,不应该用这个设计模式。
php内建了SplSubject 和 SplObserver 接口以及一个方便的SplObjectStorage类。
SplSubject 接口 需要实现3个方法:
abstract public void attach ( SplObserver $observer ) 添加(注册)一个观察者
abstract public void detach ( SplObserver $observer ) 删除一个观察者
abstract public void notify ( void ) 当状态发生改变时,通知所有观察者
SplObserver接口需要实现一个方法
abstract public void update ( SplSubject $subject ) 在目标发生改变时接收目标发送的通知;当关注的目标调用其 notify()时被调用
分析
下面构造一个需求,用户修改密码后,对其发送两种通知,一个是email通知,一个是手机短信通知。
分析需求,
1、不需要通知的返回值。
2、当目标发生状态变化时(密码修改),有多个后续处理,这时特别适合观察者。
3、监听器和目标的功能是比较分离的,不是紧密关联的。一个是发通知,一个是改数据库,这样可以借助设计模式来分解业务逻辑。
4、一般, 添加监听器的代码,放在客户端代码里写。
代码实现
总共4个文件,
User.php, 目标对象
MobileSender.php,某个监听器对象
EmailSender.php,某个监听器对象
Client.php,客户端代码,
在这个设计模式中,客户端代码还有添加监听器。
User.php
email = $email; $this->username = $username; $this->mobile = $mobile; $this->password = $password; $this->observers = new SplObjectStorage(); } 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 changePassword($newPassword) { echo __METHOD__, PHP_EOL; $this->password = $newPassword; $this->notify(); } // 专门给监听器的信息,也可以省略,然后对每个字段添加get方法 public function get_observer_info(){ return [ "email" => $this->email, "mobile" => $this->mobile, "username" => $this->username, "password" =>$this->password, ]; } }
MobileSender.php
get_observer_info(); // 真正的发送短信代码略。 echo "向 手机{$userInfo['mobile']} 发送短信成功。短信内容是:你好 {$userInfo['username']}" . "你的新密码是 {$userInfo['password']},请妥善保管", PHP_EOL; } }
EmailSender.php
get_observer_info(); // 真正的发送邮件代码略。 echo "向 {$userInfo['email']} 发送电子邮件成功。内容是:你好 {$userInfo['username']}" . "你的新密码是 {$userInfo['password']},请妥善保管", PHP_EOL; } }
Client.php:
attach($email_sender); $user->attach($mobile_sender); // 然后在对目标执行动作,顺序必须是先添加监听器,然后对象操作。 $user->changePassword('654321');
效果展示
在命令行,输入php Client.php,展示如下:
User::changePassword 向 [email protected] 发送电子邮件成功。内容是:你好 张三你的新密码是 654321,请妥善保管 向 手机13610002000 发送短信成功。短信内容是:你好 张三你的新密码是 654321,请妥善保管