PHP學習記錄----策略模式

    策略模式可以用來創建可插入,可替換,可重用的組件。

    先寫一個沒有用策略模式的例子:

Lesson.class.php:

<?php
      //課程類
	  class Lesson {
          //課程購買人數
		  private $_num;
		  //課程類型
		  private $_type;
            
          //英文課的標識
		  const ENGLISH = 1;
		  //數學課的標識
		  const MATH = 2;

		  //構造方法初始化
		  public function __construct($_num,$_type){
		    $this->_num=$_num;
			$this->_type=$_type;
		  }

		  //返回購買課程所需的費用
          public function cost(){
		    switch($this->_type){
			    case self::ENGLISH:
					  return 300*$this->_num;
				      break;
			     case self::MATH:
					  return 180*$this->_num;
				      break;
			}
		  }
          //返回購買課程的名稱
	      public function courseType(){
		       switch($this->_type){
			    case self::ENGLISH:
					  return '您購買的是英文課';
				      break;
			     case self::MATH:
					  return '您購買的是數學課';
				      break;
			    }
		  }
	  }
?>
Lesson.php:

<?php
    require 'Lesson.class.php';
    $_lesson = new Lesson(5,Lesson::ENGLISH);
	echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
	echo '<br>';
     $_lesson = new Lesson(5,Lesson::MATH);
	echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
?>
考慮第一個問題:是否可重用?   很明顯上述代碼是不可重用的,都是單獨調用。

考慮第二個問題:是否可插入?   如果我們此時再加入一門新的課程,必須往主類中添加額外的代碼,違反了高內聚,低耦合的原則,所以上述代碼也不可怎麼容易插入。

考慮第桑個問題:是否可替換?   如果將ENGLISH改爲CHINESE的話,那麼Lesson.php中也要修改,有ENGLISH的地方都要進行修改,造成連鎖反應,所以替換也不行。

當項目不斷擴展時,它的修改和維護會非常艱難。下面我們來再用繼承的方式修改一下上述的代碼:

Lesson.class.php:

<?php
      //抽象課程類
	  abstract class Lesson {
          //課程購買人數
		  protected $_num;

		  //構造方法初始化
		  public function __construct($_num){
		    $this->_num=$_num;
		  }

		  //返回購買課程所需的費用
          abstract public function cost();
          //返回購買課程的名稱
	      abstract public function courseType();
	  }
?>

English.class.php:

<?php
   class English extends Lesson {
       public function cost(){
	     return 300*$this->_num;
	   }
       public function courseType(){
	      return '您購買的是英語課程';
	   }
   }
?>

Math.class.php:

<?php
   class Math extends Lesson {
       public function cost(){
	     return 180*$this->_num;
	   }
       
	   public function courseType(){
	      return '您購買的是數學課程';
	   }
   }
?>
lesson.php:

<?php
    require 'Lesson.class.php';
	require 'English.class.php';
	require 'Math.class.php';
    $_english = new English(5);
	echo $_english->courseType().',總共需要花費'.$_english->cost();
	echo '<br>';
    $_math = new Math(5);
	echo $_math->courseType().',總共需要花費'.$_math->cost();
?>
如果我們此時想要增加一門新的課程,就不需要再在主類中做任何修改了。只需要再增加一個新的類就行。

現在我們再來進一步使用策略模式來代替繼承,因爲在以後的擴展和維護中,策略模式要優於繼承。

策略模式的組成:   1.策略類,通常由一個接口或抽象類來實現   2.具體的策略角色:包裝了相關的算法和行爲  3.環境角色:持有一個策略類的引用,最終給客戶端調用。

Lesson.class.php:

<?php
   //課程類
   class Lesson {
        //課程購買人數
		private $_num;
		
        //策略屬性,保存具體策略角色對象的引用
        private $_strategy;

		//構造方法初始化
		public function __construct($_num,$_strategy){
		  $this->_num = $_num;
		  $this->_strategy = $_strategy;
		}

		//攔截器
		public function __get($key){
		    return $this->$key;
		}

		//返回具體策略角色課程所需要的費用
		public function cost(){
			//$this表示Lesson類傳遞給English類
		   return $this->_strategy->cost($this);
		}
        //返回具體策略角色購買課程的名稱
		public function courseType(){
		    return $this->_strategy->courseType();
		}
   }
?>
English.class.php:

<?php
   class English {
       public function cost(Lesson $_lesson){
	     return 300*$_lesson->_num;
	   }
       public function courseType(){
	      return '您購買的是英語課程';
	   }
   }
?>
Math.class.php:

<?php
   class Math {
       public function cost(Lesson $_lesson){
	     return 180*$_lesson->_num;
	   }
       
	   public function courseType(){
	      return '您購買的是數學課程';
	   }
   }
?>

lesson.php:
<?php
       require 'Lesson.class.php';
	   require 'English.class.php';
	   require 'Math.class.php';
	   //通過不同的參數來改變不同的課程的行爲,這種方法實現了類切換,類切換就是多態
	   $_lesson = new Lesson(5,new Math());
       echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
	   echo '<br>';
	   $_lesson = new Lesson(5,new English());
       echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
?>
以上的代碼並不是完全形態的策略模式,下面來看進一步改進後的形式:

我們爲子類添加一個父類來統一規範子類:

Lesson.class.php:

<?php
   //課程類
   class Lesson {
        //課程購買人數
		private $_num;
		
        //策略屬性,保存具體策略角色對象的引用
        private $_strategy;

		//構造方法初始化
		public function __construct($_num,$_strategy){
		  $this->_num = $_num;
		  $this->_strategy = $_strategy;
		}

		//攔截器
		public function __get($key){
		    return $this->$key;
		}

		//返回具體策略角色課程所需要的費用
		public function cost(){
			//$this表示Lesson類傳遞給English類
		   return $this->_strategy->cost($this);
		}
        //返回具體策略角色購買課程的名稱
		public function courseType(){
		    return $this->_strategy->courseType();
		}
   }
?>
SuperClass.class.php:

<?php
     abstract class SuperCourse {
        abstract public function cost(Lesson $_lesson); 
	    abstract public function courseType();
	 }

?>
Math.class.php:

<?php
   class Math extends SuperCourse{
       public function cost(Lesson $_lesson){
	     return 180*$_lesson->_num;
	   }
       
	   public function courseType(){
	      return '您購買的是數學課程';
	   }
   }
?>
English.class.php:

<?php
   class English extends SuperCourse{
       public function cost(Lesson $_lesson){
	     return 300*$_lesson->_num;
	   }
       public function courseType(){
	      return '您購買的是英語課程';
	   }
   }
?>
lesson.php:

<?php
       require 'Lesson.class.php';
	   require 'SuperCourse.class.php';
	   require 'English.class.php';
	   require 'Math.class.php';
	   //通過不同的參數來改變不同的課程的行爲,這種方法實現了類切換,類切換就是多態
	   $_lesson = new Lesson(5,new Math());
       echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
	   echo '<br>';
	   $_lesson = new Lesson(5,new English());
       echo $_lesson->courseType().',總共花費了'.$_lesson->cost().'元';
?>
這就是一個比較正宗的策略模式-。-




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章