PHP設計模式之策略模式

簡介

策略模式定義了算法族,分別封裝起來,讓他們之間能夠相互替換。該模式讓算法獨立於使用它的客戶而獨立變化。php

組成

  1. 抽象策略角色: 策略類,一般由一個接口或者抽象類實現。html

  2. 具體策略角色:包裝了相關的算法和行爲。算法

  3. 環境角色:持有一個策略類的引用,最終給客戶端調用。segmentfault

應用場景

  1. 多個類只區別在表現行爲不一樣,可使用策略模式,在運行時動態選擇具體要執行的行爲。工具

  2. 須要在不一樣狀況下使用不一樣的策略(算法),或者策略還可能在將來用其它方式來實現。this

  3. 對客戶隱藏具體策略(算法)的實現細節,彼此徹底獨立。設計

實現

步驟

  1. 定義抽象角色類(定義好各個實現的共同抽象方法)code

  2. 定義具體策略類(具體實現父類的共同方法)htm

  3. 定義環境角色類(接收保存實例,統一執行策略類接口方法)對象

代碼

<?php
header('Content-Type:text/html;charset=utf-8');
/**
 * 策略模式演示代碼
 *
 * 爲了更好地突出「策略」,咱們這裏以出行爲例演示,平常出行大概分爲如下幾種工具:自駕車,公交車,地鐵,火車,飛機,輪船
 *
 * 下面一塊兒看代碼,領會何爲策略模式
 */

/**
 * Interface Travel 抽象策略角色
 * 約定具體方法
 */
interface Travel
{
    public function go();
}

/**
 * Class selfDriving 具體策略角色
 * 自駕車
 */
class bySelfDriving implements Travel
{
    public function go()
    {
        echo '我本身開着車出去玩<br>';
    }
}

/**
 * Class byBus具體策略角色
 * 乘公交
 */
class byBus implements Travel {
    public function go()
    {
        echo '我乘公交出去玩<br>';
    }
}

/**
 * Class byMetro 具體策略角色
 * 乘地鐵
 */
class byMetro implements Travel
{
    public function go()
    {
        echo '我乘地鐵出去玩<br>';
    }
}

/**
 * Class byTrain 具體策略角色
 * 乘火車
 */
class byTrain implements Travel
{
    public function go()
    {
        echo '我乘火車出去玩<br>';
    }
}

/**
 * Class byAirplane 具體策略角色
 * 乘飛機
 */
class byAirplane implements Travel
{
    public function go()
    {
        echo '我乘飛機出去玩<br>';
    }
}

/**
 * Class bySteamship 具體策略角色
 * 乘輪船
 */
class bySteamship implements Travel
{
    public function go()
    {
        echo '我乘輪船出去玩<br>';
    }
}

/**
 * Class Mine 環境角色
 */
class Mine{
    private $_strategy;
    private $_isChange = false;

    /**
     * 構造方法
     * 此處使用到了依賴注入和類型約束的概念,詳情請參考
     * 1.聊一聊PHP的依賴注入(DI) 和 控制反轉(IoC)
     * @link https://segmentfault.com/a/1190000007209266
     * 2.淺談PHP的類型約束
     * @link https://segmentfault.com/a/1190000007226476
     *
     * @param Travel $travel
     */
    public function __construct(Travel $travel)
    {
        $this->_strategy = $travel;
    }

    /**
     * 改變出行方式
     *
     * @param Travel $travel
     */
    public function change(Travel $travel)
    {
        $this->_strategy = $travel;
        $this->_isChange = true;
    }

    public function goTravel()
    {
        if ($this->_isChange) {
            echo '如今改變主意,';
            $this->_strategy->go();
        } else {
            $this->_strategy->go();
        }

    }
}

/**
 * 客戶端使用
 */
$strategy = new Mine(new byBus());
// 乘公交
$strategy->goTravel();
// 乘地鐵
$strategy->change(new byMetro());
$strategy->goTravel();
// 自駕車
$strategy->change(new bySelfDriving());
$strategy->goTravel();

// 其餘根據具體應用選擇實現

運行結果

我乘公交出去玩
如今改變主意,我乘地鐵出去玩
如今改變主意,我本身開着車出去玩

優缺點

優勢

  1. 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承能夠把公共的代碼轉移到父類裏面,從而避免重複的代碼。

  2. 策略模式提供了能夠替換繼承關係的辦法。繼承能夠處理多種算法或行爲。若是不是用策略模式,那麼使用算法或行爲的環境類就可能會有一些子類,每個子類提供一個不一樣的算法或行爲。可是,這樣一來算法或行爲的使用者就和算法或行爲自己混在一塊兒。決定使用哪種算法或採起哪種行爲的邏輯就和算法或行爲的邏輯混合在一塊兒,從而不可能再獨立演化。繼承使得動態改變算法或行爲變得不可能。

  3. 使用策略模式能夠避免使用多重條件轉移語句。多重轉移語句不易維護,它把採起哪種算法或採起哪種行爲的邏輯與算法或行爲的邏輯混合在一塊兒,通通列在一個多重轉移語句裏面,比使用繼承的辦法還要原始和落後。

缺點

  1. 客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道全部的算法或行爲的狀況。

  2. 策略模式形成不少的策略類,每一個具體策略類都會產生一個新類。有時候能夠經過把依賴於環境的狀態保存到客戶端裏面,而將策略類設計成可共享的,這樣策略類實例能夠被不一樣客戶端使用。換言之,可使用享元模式來減小對象的數量。

附錄

相關文章
相關標籤/搜索