/**
- 優(yōu)才網(wǎng)公開課示例代碼
- 觀察者模式 Observer
- @author 優(yōu)才網(wǎng)全棧工程師教研組
- @seehttp://www.ucai.cn
*/
function output($string) {
echo $string . "\n";
}
//訂單數(shù)據(jù)對象簡單模擬,這個是實際需要被觀察的對象(Subject),但是我們將其獨立伺绽,然后
//通過構(gòu)造方法傳入到我們模式中的Subject中,這樣使具體業(yè)務更加獨立
class Order{
//訂單號
private $id = '';
//用戶ID
private $userId = '';
//用戶名
private $userName = '';
//價格
private $price = '';
//下單時間
private $orderTime = '';
//訂單數(shù)據(jù)填充簡單模擬鉴吹,實際應用中可能會讀取用戶表單輸入并處理
public function __set($name, $value){
if(isset($this->$name)){
$this->$name = $value;
}
}
//獲取訂單屬性
public function __get($name){
if(isset($this->$name)) {
return $this->$name;
}
return "";
}
}
//被觀察者, 負責維護觀察者并在變化發(fā)生是通知觀察者
class OrderSubject implements SplSubject {
private $observers;
private $order;
public function __construct(Order $order) {
$this->observers = new SplObjectStorage();
$this->order = $order;
}
//增加一個觀察者
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);
}
}
//返回主體對象的具體實現(xiàn)东揣,供觀察者調(diào)用
public function getOrder() {
return $this->order;
}
}
//記錄業(yè)務數(shù)據(jù)日志 (ActionLogObserver),實際可能還要抽象一層以處理不同的Action(業(yè)務操作)铲敛,這里省略
class ActionLogObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//實際應用可能會寫到日志文件中待错,這里直接輸出
output( "[OrderId:{$order->id}] [UseId:{$order->userId}][Price:{$order->price}]" );
}
}
//給用戶發(fā)送訂單確認郵件 (UserMailObserver)
class UserMailObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//實際應用會調(diào)用郵件發(fā)送服務如sendmail籽孙,這里直接輸出
output( "Dear {$order->userName}: Your order {$order->id} wasconfirmed!" );
}
}
//給管理人員發(fā)訂單處理通知郵件 (AdminMailObserver)
class AdminMailObserver implements SplObserver{
public function update(SplSubject $subject) {
$order = $subject->getOrder();
//實際應用會調(diào)用郵件發(fā)送服務如sendmail,這里直接輸出
output( "Dear Manager: User{$order->userName}(ID:{$order->userId}) submitted a new order{$order->id}, please handle it ASAP!" );
}
}
//假設(shè)的DB類火俄,便于測試犯建,實際會存入真實數(shù)據(jù)庫
class FakeDB{
public function save($data){
return true;
}
}
class Client {
public static function test() {
//初始化一個訂單數(shù)據(jù)
$order= new Order();
$order->id = 1001;
$order->userId = 9527;
$order->userName = "God";
$order->price = 20.0;
$order->orderTime = time();
//綁定觀察者
$subject = new OrderSubject($order);
$actionLogObserver = new ActionLogObserver();
$userMailObserver = newUserMailObserver();
$adminMailObserver = new AdminMailObserver();
$subject->attach($actionLogObserver);
$subject->attach($userMailObserver);
$subject->attach($adminMailObserver);
//向數(shù)據(jù)庫保存訂單
$db =new FakeDB();
$result = $db->save($order);
if($result){
//通知觀察者
$subject->notify();
}
}
}
Client::test();
?>