1. 程式人生 > >PHP設計模式之策略模式(Strategy)瞭解下

PHP設計模式之策略模式(Strategy)瞭解下

這個策略模式,意思就是定義一系列演算法,把它們一個個封裝起來,並且使它們可相互替換,使用得演算法的變化可獨立於使用它的客戶,簡單來講就是,策略模式設計幫助構建的物件不必自身包含邏輯,而是能夠根據需要利用其他物件中的演算法。

來看下應用場景:

       1、 多個類只區別在表現行為不同,可以使用Strategy模式,在執行時動態選擇具體要執行的行為。

       2、 需要在不同情況下使用不同的策略(演算法),或者策略還可能在未來用其它方式來實現。

       3、 對客戶隱藏具體策略(演算法)的實現細節,彼此完全獨立。

       4、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類,策略模式只適用於客戶端知道所有的演算法或行為的情況。

       5、 策略模式造成很多的策略類,每個具體策略類都會產生一個新類。

有點模糊是吧,咱就來看一個完整的應用場景:

  1. 例如有一個CD類,我們類儲存了CD的資訊。
  2. 原先的時候,我們在CD類中直接呼叫getCD方法給出XML的結果
  3. 隨著業務擴充套件,需求方提出需要JSON資料格式輸出
  4. 這個時候我們引進了策略模式,可以讓使用方根據需求自由選擇是輸出XML還是JSON

大概瞭解了之後,咱們來看一個程式碼例項,我在網上找的啊,比較簡單,大家可以根據自己需要的來擴充套件一下,如下:

    <?php
    //策略模式
    //cd類
    class cd {
    	protected $cdArr;
    	
    	public function __construct($title, $info) { 
    		$this->cdArr['title'] = $title;
    		$this->cdArr['info']  = $info;
    	}
    	
    	public function getCd($typeObj) {
    		return $typeObj->get($this->cdArr);
    	} 
    }
     
    class json {
    	public function get($return_data) {
    		return json_encode($return_data);
    	}
    }
     
    class xml {
    	public function get($return_data) {
    			$xml = '<?xml version="1.0" encoding="utf-8"?>';
    			$xml .= '<return>';
    				$xml .= '<data>' .serialize($return_data). '</data>';
    			$xml .= '</return>';
    			return $xml;
    	}
    }
     
    $cd = new cd('cd_1', 'cd_1');
    echo $cd->getCd(new json);
    echo $cd->getCd(new xml);

咱們接下來,再來了解一下一個網上比較經典的案例,來看張圖片:

上面圖片的意思可以按著下面這個方式來理解:

1.Joe做了一套相當成功的模擬鴨子的遊戲。設計了一個超類Duck,然後讓各種鴨子繼承這個類。

2.後來客戶提出要讓鴨子有飛的能力。所以Joe就在超類中加了個fly()方法,這樣下面的子類都有飛行的行為。

   問題來了:1>原來Duck的子類中竟然有橡皮鴨,橡皮鴨是不會飛的。——Joe用過載的方式,把橡皮鴨的fly()方法設定為空.

                     2>覆蓋fly(),我們看到了橡皮鴨的fly()裡,沒有任何程式碼,如果以後我們再新增別的不會飛的鴨子,那我麼還要這麼處理嗎?——那麼程式碼重複了!

3.上面2的方式我們知道是有問題的,所以Joe想到把Duck做成介面,這樣每個子類必須實現Duck裡的方法。這樣就保證每個鴨子都能根據自己的需要新增行為。

     問題來了:產品經常處於更新中,規格也在不斷的變化。導致每當有新鴨子的時候,Joe就要被迫檢查一遍子類是否覆蓋了fly()方法。——當你修改某個行為的時候,你必須得往下追蹤並在每一個定義此行為的類中修改它。

4.綜合以上問題,Joe想到了把那些變化的部分從不變化的位置中抽出來。比如,我們對fly()行為,做了單獨的介面FlyBehavior。如果鴨子想要飛行功能的時候,我們就讓鴨子實現FlyBehavior.

5.深造:我們想讓鴨子有不同的飛行功能,讓它在執行時候做不同的飛行動作。讓鴨子類實現介面,只能讓鴨子有一種行為。

好,接下來看下程式碼例項:


<?php
interface FlyBehavior{
    public function fly();
}
 
class FlyWithWings implements FlyBehavior{
    public function fly(){
        echo "Fly With Wings \n";
    }
}
 
class FlyWithNo implements FlyBehavior{
    public function fly(){
        echo "Fly With No Wings \n";
    }
}
class Duck{
    private $_flyBehavior;
    public function performFly(){
        $this->_flyBehavior->fly();
    }
 
    public function setFlyBehavior(FlyBehavior $behavior){
        $this->_flyBehavior = $behavior;
    }
}
 
class RubberDuck extends Duck{
}
// Test Case
$duck = new RubberDuck();
 
/*  想讓鴨子用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithWings());
$duck->performFly();            
 
/*  想讓鴨子不用翅膀飛行 */
$duck->setFlyBehavior(new FlyWithNo());
$duck->performFly();

咱們可以來總結下在開發過程中,這些設計模式的設計原則,如下:

1.找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起;

2.針對介面程式設計,不針對實現程式設計;

3.多用組合,少用繼承;

好啦,本次記錄就到這裡了。

如果感覺不錯的話,請多多點贊支援哦。。。