1. 程式人生 > >5. php設計模式:策略模式的實際應用

5. php設計模式:策略模式的實際應用

原文地址

最近寫了一個整合各家支付的開源專案(支付寶與微信)。專案地址。讓呼叫支付變得更加簡單、統一。目前已經在公司商城推行使用,上海一米市集也採用了這個支付整合專案。

我可不是打廣告哦,只是為了讓大家可以有一個只管的瞭解渠道。可以去看看。

今天主要聊的不是支付,而是說說其中使用的一個設計模式:策略模式。

策略模式的定義解析

策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)。

這是書本上給的定義,是不是完全搞不懂?我結合支付,再來給你解釋一下,一定就赫然開朗啦!

首先是這句 讓演算法獨立於使用它的客戶而變化 (我是倒著在分析哦)。
這是什麼意思?也就是說實現一個功能,有多個方法,而選擇這個方法的控制權不要交給客戶端,也就說了,我換了實現方法,客戶端是不需要改程式碼的。

那麼要做到這樣子,必然提供給客戶端的一個穩定的呼叫類(稱為環境類),首先呼叫這個類能夠產生一個具體演算法的例項,其次這個呼叫類,還需要公佈一個介面,讓客戶端呼叫實現具體功能。

那麼做到以上,無論實現多少種雙方,客戶端的呼叫都是不變的。控制權都在這個呼叫類裡邊,由它來決定到底採用哪種演算法。

下面來接著說演算法部分。如果需要 環境類 提供一個實現具體功能的介面,那麼這些演算法必然實現了一個公共介面(稱為抽象策略類)。才能確保有相同的方法提供出來。然後具體的演算法都要實現這個介面。這也就是上面定義中的 將每一個演算法封裝起來

每一個具體的演算法稱為:具體策略類

不知道這個解釋大家清楚定義了沒有,如果還不清楚,看類圖

類圖演示

策略模式包含的角色如下:

  • Context: 環境類
  • Strategy: 抽象策略類
  • ConcreteStrategy: 具體策略類

image

這下子是不是很清楚了?策略模式是使用非常廣泛的一個設計模式。他很好的提現了:控制反轉、依賴注入等思想。有同學說,不想看文字,有本事上程式碼呀!嗯,我喜歡,新鮮出爐的程式碼來了

策略模式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 這個類中,其實還使用了 簡單工廠 這個模式。這裡想給大家說明的是,其實設計模式只是一些編碼的技巧,完全可以自由搭配組合,基本思想就是 設計模式的六大原則

當然,實際編碼中也沒有必要非要都實現這六大原則。這個也沒有什麼規範,只能大家多去實踐,然後自己約定出一套適合業務的規範就好。