1. 什麼是策略模式
簡單的講就是實現一個問題的多種方法就是策略設計模式,我們在開發微信公衆號時,有一組被動接收微信消息的接口(例如:普通文本消息、關注事件消息、取消關注事件消息……),針對不同的消息有多種處理方式,有處理文本有處理關注事件的等等我們使用的邏輯算法都不一樣,當然啦業務邏輯也不一樣啦。像這種情況我們可以嘗試使用策略模式
來進行設計,其中策略模式
屬於行爲型設計模式類型。設計模式的主要原則之一就是封裝變化的內容,對於發送到PHP類的不同類型的請求,分別有不同的算法來處理。類圖如下:
在策略模式
在模式中我們要避免在context參與者中使用條件語句或case語句,使用條件語句可能會導致維護想當困難。如果要改變一個策略(封裝的算法邏輯)或新增一個具體的算法策略時,那麼context參與者就會被動的再去添加這個具體的策略,並對其進行維護。如果實現某個問題的具體策略想當的多那麼context就會變得臃腫使其難以維護,同時也違反了面向對象編程中的開放封閉原則
不是嗎?如果讀者還不懂什麼是開發封閉原則,建議去看doris的http://blog.csdn.net/dorisnzy/article/details/76222881的博客,這樣更有助於理解設計模式開發中的奧妙。
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的博客初探面向對象與設計模式-簡單工廠模式。
完!