1. 程式人生 > 實用技巧 >php 策略模式

php 策略模式

策略模式定義了一族相同型別的演算法,演算法之間獨立封裝,並且可以互換代替。

這些演算法是同一型別問題的多種處理方式,他們具體行為有差別。

每一個演算法、或說每一種處理方式稱為一個策略。

在應用中,就可以根據環境的不同,選擇不同的策略來處理問題。

以陣列輸出為例。

陣列的輸出有序列化輸出、JSON字串輸出和陣列格式輸出等方式。

每種輸出方式都可以獨立封裝起來,作為一個策略。

應用時,如要把陣列儲存到資料庫中,可以用序列化方式輸出。

要提供給APP作介面,可以用JSON字串輸出。

其他程式呼叫,則直接輸出陣列格式。

1 問題

在沒有設計模式的情況,我們用一個類集中處理陣列輸出,如下:

/**
 * 根據給定型別,將陣列轉換後輸出
 */
class Output
{
    public function render($array, $type = '')
    {
        if ($type === 'serialize') {
            return serialize($array);
        } elseif ($type === 'json') {
            return json_encode($array);
        } else {
            return $array;
        }
    }
}

客戶端直接使用這個類來處理陣列,就能達到效果:

/**
 * 客戶端程式碼
 */
$test = ['a', 'b', 'c'];

// 例項化輸出類
$output = new Output();

// 直接返回陣列
$data = $output->render($test, 'array');

// 返回JSON字串
$data = $output->render($test, 'json');

這種方法的優點是簡單、快捷,在小方案中使用非常合適。

但是,如果是一個複雜方案,包括大量的處理邏輯需要封裝,或者處理方式變動較大,則就顯得混亂。

當需要新增一種演算法,就必須修改Output

類,影響原有程式碼,可擴充套件性差。

如果輸出方式很多,if-elseswitch-case語句也會很多,程式碼混亂難以維護。

2 解決

那如何用策略模式解決這個問題呢?

策略模式將各種方案分離開來,讓操作者根據具體的需求,動態地選擇不同的策略方案。

2.1 策略類

首先,定義一系列的策略類,它們獨立封裝,並且遵循統一的介面。

/**
 * 策略介面
 */
interface OutputStrategy
{
    public function render($array);
}

/**
 * 策略類1:返回序列化字串
 */
class SerializeStrategy implements OutputStrategy
{
    public function render($array)
    {
        return serialize($array);
    }
}

/**
 * 策略類2:返回JSON編碼後的字串
 */
class JsonStrategy implements OutputStrategy
{
    public function render($array)
    {
        return json_encode($array);
    }
}

/**
 * 策略類3:直接返回陣列
 */
class ArrayStrategy implements OutputStrategy
{
    public function render($array)
    {
        return $array;
    }
}

以後的維護過程中,以上程式碼都不需修改了。

如果需要增加輸出方式,重新建一個類就可以了。

(根據FIG-PSR規範,一個類就是一個獨立的PHP檔案。)

2.2 環境類

環境角色用來管理策略,實現不同策略的切換功能。

同樣,一旦寫好,環境角色類以後也不需要修改了。

/**
 * 環境角色類
 */
class Output
{
    private $outputStrategy;

    // 傳入的引數必須是策略介面的子類或子類的例項
    public function __construct(OutputStrategy $outputStrategy)
    {
        $this->outputStrategy = $outputStrategy;
    }

    public function renderOutput($array)
    {
        return $this->outputStrategy->render($array);
    }
}

2.3 客戶端程式碼

在客戶端中,策略模式通過給予不同的具體策略,來獲取不同的結果。

/**
 * 客戶端程式碼
 */
$test = ['a', 'b', 'c'];

// 需要返回陣列
$output = new Output(new ArrayStrategy());
$data = $output->renderOutput($test);

// 需要返回JSON
$output = new Output(new JsonStrategy());
$data = $output->renderOutput($test);

對於較為複雜的業務邏輯顯得更為直觀,擴充套件也更為方便。

3 特點

策略模式主要用來分離演算法,根據相同的行為抽象來做不同的具體策略實現。

策略模式結構清晰明瞭、使用簡單直觀。並且耦合度相對而言較低,擴充套件方便。同時操作封裝也更為徹底,資料更為安全。

當然策略模式也有缺點,就是隨著策略的增加,子類也會變得繁多。

但缺點並不會影響系統執行,所以在複雜業務中應該考慮使用。

策略模式UML圖: