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().'元';
?>
这就是一个比较正宗的策略模式-。-




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