策略模式可以用來創建可插入,可替換,可重用的組件。
先寫一個沒有用策略模式的例子:
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().'元';
?>
這就是一個比較正宗的策略模式-。-