[url=http://xieye.iteye.com/blog/2404077]php設計模式(1)-- 觀察者模式 -- spl標準寫法[/url]
[url=http://xieye.iteye.com/blog/2404082]php設計模式(2)-- 觀察者模式 -- 用trait來改進的寫法[/url]
[url=http://xieye.iteye.com/blog/2404140]php設計模式(3)-- 責任鏈(職責鏈)模式[/url]
[url=http://xieye.iteye.com/blog/2404169]php設計模式(4)-- 裝飾器模式[/url]
[size=x-large]分析[/size]
我們來重新思考一下前面的代碼,發現有一個不足,我僅僅是想實現觀察者,如果每個想實現觀察者的類,都寫那麼多代碼,不太好。
這裏我不使用繼承,原因:php只允許單繼承,如果爲了實現觀察者模式繼承的話,就不能繼承別的類了。
於是使用trait來解決,效果棒呆!對於前文的4個文件,修改User.php,再添加一個MySqlSubject.php,這樣的話,兩個觀察者類,和客戶端代碼無需任何修改,
最終,User類的代碼只有他自己的業務邏輯,無關的代碼被放到通用類MySqlSubject中,代碼十分清爽,且可以重用。
[size=x-large]代碼[/size]
MySplSubject.php
<?php
// 本類是可以通用的
trait MySplSubject {
/**
* @var SplObjectStorage
*/
private $observers = NULL;
private function create_observers(){
if ($this->observers==null) {
$this->observers = new SplObjectStorage();
}
}
public function attach(SplObserver $observer) {
$this->create_observers();
$this->observers->attach($observer);
}
public function detach(SplObserver $observer) {
$this->create_observers();
$this->observers->detach($observer);
}
public function notify() {
$this->create_observers();
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
User.php
<?php
class User implements SplSubject {
// 由trait來實現接口
use MySplSubject;
private $email;
private $username;
private $mobile;
private $password;
public function __construct($email, $username, $mobile, $password) {
$this->email = $email;
$this->username = $username;
$this->mobile = $mobile;
$this->password = $password;
}
// 這是業務邏輯
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,
];
}
}
效果展示同前文一樣:
User::changePassword
向 [email protected] 發送電子郵件成功。內容是:你好 張三你的新密碼是 654321,請妥善保管
向 手機13610002000 發送短信成功。短信內容是:你好 張三你的新密碼是 654321,請妥善保管