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-else
或switch-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圖: