php設計模式(1)-- 觀察者模式 -- spl標準寫法

我的設計模式系列文章
[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]


本文講觀察者模式。
部分代碼來源:
https://www.ibm.com/developerworks/cn/opensource/os-cn-observerspl/

[size=x-large]概述[/size]

[b][size=large]個人的心得體會:最重要的一點,目標對象,給觀察者對象發通知時,不需要對方的返回值,僅僅把通知下發就完事。[/size][/b]
這是最重要的。如果需要返回,不應該用這個設計模式。

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()時被調用

[size=x-large]分析[/size]

下面構造一個需求,用戶修改密碼後,對其發送兩種通知,一個是email通知,一個是手機短信通知。
分析需求,
1、不需要通知的返回值。
2、當目標發生狀態變化時(密碼修改),有多個後續處理,這時特別適合觀察者。
3、監聽器和目標的功能是比較分離的,不是緊密關聯的。一個是發通知,一個是改數據庫,這樣可以藉助設計模式來分解業務邏輯。
4、一般,[b]添加監聽器的代碼,放在客戶端代碼裏寫[/b]。

[size=x-large]代碼實現[/size]

總共4個文件,
User.php, 目標對象
MobileSender.php,某個監聽器對象
EmailSender.php,某個監聽器對象
Client.php,客戶端代碼,
在這個設計模式中,客戶端代碼還有添加監聽器。

User.php

<?php

class User implements SplSubject {

private $email;
private $username;
private $mobile;
private $password;
/**
* @var SplObjectStorage
*/
private $observers = NULL;

public function __construct($email, $username, $mobile, $password) {
$this->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

<?php
class MobileSender implements SplObserver {

public function update(SplSubject $subject) {

$userInfo = $subject->get_observer_info();
// 真正的發送短信代碼略。
echo "向 手機{$userInfo['mobile']} 發送短信成功。短信內容是:你好 {$userInfo['username']}" .
"你的新密碼是 {$userInfo['password']},請妥善保管", PHP_EOL;

}
}


EmailSender.php

<?php
class EmailSender implements SplObserver {

public function update(SplSubject $subject) {

$userInfo = $subject->get_observer_info();
// 真正的發送郵件代碼略。
echo "向 {$userInfo['email']} 發送電子郵件成功。內容是:你好 {$userInfo['username']}" .
"你的新密碼是 {$userInfo['password']},請妥善保管", PHP_EOL;

}
}


Client.php:

<?php
header('Content-Type: text/plain');

function __autoload($class_name) {
require_once "$class_name.php";
}

//定義目標對象
$user = new User('[email protected]', '張三', '13610002000', '123456');

// 添加監聽器在客戶端,
$email_sender = new EmailSender();
$mobile_sender = new MobileSender();
$user->attach($email_sender);
$user->attach($mobile_sender);

// 然後在對目標執行動作,順序必須是先添加監聽器,然後對象操作。
$user->changePassword('654321');



[size=x-large]
效果展示[/size]

在命令行,輸入php Client.php,展示如下:

User::changePassword
[email protected] 發送電子郵件成功。內容是:你好 張三你的新密碼是 654321,請妥善保管
向 手機13610002000 發送短信成功。短信內容是:你好 張三你的新密碼是 654321,請妥善保管
發佈了312 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章