初探PHP面向物件與設計模式-策略模式
1. 什麼是策略模式
簡單的講就是實現一個問題的多種方法就是策略設計模式,我們在開發微信公眾號時,有一組被動接收微信訊息的介面(例如:普通文字訊息、關注事件訊息、取消關注事件訊息……),針對不同的訊息有多種處理方式,有處理文字有處理關注事件的等等我們使用的邏輯演算法都不一樣,當然啦業務邏輯也不一樣啦。像這種情況我們可以嘗試使用策略模式
來進行設計,其中策略模式
屬於行為型設計模式型別。設計模式的主要原則之一就是封裝變化的內容,對於傳送到PHP類的不同型別的請求,分別有不同的演算法來處理。類圖如下:
在策略模式
在模式中我們要避免在context參與者中使用條件語句或case語句,使用條件語句可能會導致維護想當困難。如果要改變一個策略(封裝的演算法邏輯)或新增一個具體的演算法策略時,那麼context參與者就會被動的再去新增這個具體的策略,並對其進行維護。如果實現某個問題的具體策略想當的多那麼context就會變得臃腫使其難以維護,同時也違反了面向物件程式設計中的開放封閉原則
2. 不良的程式碼設計
接下來演示一下工作中沒有采用策略模式虛擬碼。案例為被動接收微信事件訊息,虛擬碼如下:
<?php
/**
* 被動接收微信訊息
* @author doris <[email protected]>
*/
class WechatRequest
{
// 接收到的訊息體
private $msg;
/**
* 訊息入口
*/
public function index()
{
$this->msg = file_get_contents('php://input');
// ……xml處理msg資訊省略……
switch($this->msg['msgtype']) {
case 'text':
// 處理普通文字訊息的業務邏輯演算法
$this->text();
break;
case 'image' :
// 處理圖片的業務邏輯演算法
$this->image();
break;
// ……等等其它業務邏輯演算法……
}
}
/**
* 處理text文字訊息
*/
private function text()
{
// 業務邏的處理
}
/**
* 處理image文字
*/
private function iamge()
{
// 業務邏輯的處理
}
}
// 呼叫
$wechat = new WechatRequest;
$wechat->index();
程式碼分析:
這種開發把所有接收不同型別的訊息都集中到了一個類中完成會使得業務程式碼會越來越臃腫,可擴充套件性不好,可讀性也不好,如果下一個開發者來維護這個程式碼會很難入手。
3. 使用策略模式對程式碼進行優化
策略模式中參與者有2個身份,一個是實現某個問題的詳細策略,一個是context參與者,虛擬碼如下:
(1)詳細策略具體實現的演算法組參與者
<?php
/**
* 策略介面規範要實現的方法
* @author doris <[email protected]>
*/
interface class IrequestStrategy
{
/**
* 實現接收各型別訊息並處理
*/
abstract public function dispose();
}
/**
* 接收並處理普通文字訊息
* @author doris <[email protected]>
*/
class Text implememt IrequestStrategy
{
/**
* 處理普通文字訊息
*/
public function dispose()
{
// 實現具體的業務邏輯
}
}
/**
* 接收並處理圖片訊息
* @author doris <[email protected]>
*/
class Image implement IrequestStrategy
{
public function dispose()
{
// 實現具體的業務邏輯
}
}
// 處理其它訊息型別……
(2)context參與者
<?php
/**
* 根據上下文實現具體的策略
* @author doris <[email protected]>
*/
class Context
{
private $strategy;
/**
* 初始化工作
* @param object $strategy 實現具體訊息的詳細策略演算法的策略物件
*/
public function __construct(IrequestStrategy $strategy)
{
$this->strategy = $strategy;
}
/**
* 接收並處理各型別的訊息
*/
public function dispose()
{
$this->strategy->dispose();
}
}
(3)client端呼叫
<?php
$msg = file_get_contents('php://input');
// ……xml處理msg資訊省略……
switch($msg['msgtype']) {
case 'text':
// 處理普通文字訊息的業務邏輯演算法
$strategy = new Text;
;
break;
case 'image':
// 處理圖片的業務邏輯演算法
$strategy = new Image;
break;
// ……等等其它業務邏輯演算法……
}
$context = new Context($strategy);
$context->dispose();
程式碼分析:
這種程式碼的設計可以將各個型別的訊息抽離出來分別實現各種不同的演算法,程式碼看起來非常簡潔,可擴充套件性好,可讀性也好,如果什麼時候微信公眾號再加一個其它訊息型別,不需要對原有的業務程式碼進行修改,只需要擴充套件一個具體的策略演算法就能夠輕鬆的實現。
擴充套件:
除了像接收微信並處理微信各型別的訊息事件時可以用策略模式以外,比如系統中使用多種快取機制、多種資料庫機制、及資料庫增刪查改等等這些,都可以使用策略模式來進行設計。
4. 補充說明
客戶端呼叫的時候如果再加一個其它的訊息型別時還是會去修改原有的程式碼,並且當訊息型別非常多的時候程式碼也還是會變得越來越臃腫,所以我們還可以用簡單工廠模式對其進行設計。這部分的實現請參考doris的部落格初探面向物件與設計模式-簡單工廠模式。
完!