5. php設計模式:策略模式的實際應用
最近寫了一個整合各家支付的開源專案(支付寶與微信)。專案地址。讓呼叫支付變得更加簡單、統一。目前已經在公司商城推行使用,上海一米市集也採用了這個支付整合專案。
我可不是打廣告哦,只是為了讓大家可以有一個只管的瞭解渠道。可以去看看。
今天主要聊的不是支付,而是說說其中使用的一個設計模式:策略模式。
策略模式的定義解析
策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)。
這是書本上給的定義,是不是完全搞不懂?我結合支付,再來給你解釋一下,一定就赫然開朗啦!
首先是這句 讓演算法獨立於使用它的客戶而變化 (我是倒著在分析哦)。
這是什麼意思?也就是說實現一個功能,有多個方法,而選擇這個方法的控制權不要交給客戶端,也就說了,我換了實現方法,客戶端是不需要改程式碼的。
那麼要做到這樣子,必然提供給客戶端的一個穩定的呼叫類(稱為環境類),首先呼叫這個類能夠產生一個具體演算法的例項,其次這個呼叫類,還需要公佈一個介面,讓客戶端呼叫實現具體功能。
那麼做到以上,無論實現多少種雙方,客戶端的呼叫都是不變的。控制權都在這個呼叫類裡邊,由它來決定到底採用哪種演算法。
下面來接著說演算法部分。如果需要 環境類 提供一個實現具體功能的介面,那麼這些演算法必然實現了一個公共介面(稱為抽象策略類)。才能確保有相同的方法提供出來。然後具體的演算法都要實現這個介面。這也就是上面定義中的 將每一個演算法封裝起來
不知道這個解釋大家清楚定義了沒有,如果還不清楚,看類圖
類圖演示
策略模式包含的角色如下:
- Context: 環境類
- Strategy: 抽象策略類
- ConcreteStrategy: 具體策略類
這下子是不是很清楚了?策略模式是使用非常廣泛的一個設計模式。他很好的提現了:控制反轉、依賴注入等思想。有同學說,不想看文字,有本事上程式碼呀!嗯,我喜歡,新鮮出爐的程式碼來了
策略模式PHP程式碼實現
在整個模式中,Strategy 起著承上啟下的作用。我就先來實現它
interface ChargeStrategy
{
public function charge();
}
OK,抽象策略類就完成了,他的主要目的就是規範一個必須要實現的方法,環境類依賴這個介面進行程式設計。
下面接著寫演算法的實現。還是以支付寶支付、微信支付為例。對於使用者來說他要實現的功能是支付。那麼支付又有多種選擇(多種演算法)。但是客戶端不需要做出選擇,他把這個權利讓 環境類 去選擇。這樣子客戶端就簡單了。所有的演算法需要實現 策略類介面。
// 支付寶策略類
class AliCharge implements ChargeStrategy
{
public function charge()
{
// 完成支付寶的相關邏輯
}
}
// 微信策略類
class WxCharge implements ChargeStrategy
{
public function charge()
{
// 完成微信的相關邏輯
}
}
這裡宣告一下,這裡為了純粹的把 策略模式 講明白,拋開了很多細枝末節,真正的支付中的實現,大家可以去看看專案的原始碼。
final class ChargeContext
{
/**
* @var ChargeStrategy $charge
*/
private $charge;
public function initInstance($channel)
{
if ($channel == 'ali') {
$this->charge = new AliCharge;
} elseif ($chananel == 'wx') {
$this->charge = new WxCharge;
} else {
$this->charge = null;
}
}
public function charge()
{
if (is_null($this->charge)) {
exit('初始化錯誤');
}
$this->charge->charge();
}
}
以上就基本完成了,而對於客戶端來說,就非常簡單啦。
// 獲取使用者選擇的支付方式
$channel = trim($_GET['channel']);
$context = new ChargeContext();
// 初始化支付例項
$context->initInstance($channel);
// 呼叫功能
$context->charge();
程式碼寫完了,不知道大家有沒有感受到好處,這個模式很好的實現了開閉原則。比如說:現在新增加了一個PayPal支付方式。那麼只需要新增一個PayPal的策略演算法。在ChargeContext中把對應的例項初始化加進去,其他地方都不需要動的。
體會
最後再說幾句,不知道大家注意到沒有,在 ChargeContext
這個類中,其實還使用了 簡單工廠 這個模式。這裡想給大家說明的是,其實設計模式只是一些編碼的技巧,完全可以自由搭配組合,基本思想就是 設計模式的六大原則
當然,實際編碼中也沒有必要非要都實現這六大原則。這個也沒有什麼規範,只能大家多去實踐,然後自己約定出一套適合業務的規範就好。