1. 解析器模式//解析器內容類別//用於存放運算式的運算結果,並且能根據傳入的運算式返回當初記錄的結果class InterpreterContext{ private $expressionstore=array(); //將對象放進array裡面,索引號是對象ID號 function replace(Expression $exp,$value){ $this->expressionstore[$exp->getKey()]=$value; } function lookup(Expression $exp){ return $this->expressionstore[$exp->getKey()]; }}abstract class Expression{ private static $keyCount=0; private $key; abstract function interpret(InterpreterContext $context); //每一個對象都有一個唯一的key function getKey(){ if(!isset($this->key)){ $this->key=++self::$keyCount; } return $this->key; }}//字串class LiteralExpression extends Expression{ private $value; function __construct($value){ $this->value=$value; } function interpret(InterpreterContext $context){ $context->replace($this, $this->value); }}//變數class VariableExpression extends Expression{ private $value; private $name; function __construct($name,$value=null){ $this->name=$name; $this->value=$value; } function setValue($value){ $this->value=$value; } function getKey(){ return $this->name; } function interpret(InterpreterContext $context){ if(!is_null($this->value)){ $context->replace($this, $this->value); //設定為空白,可以避免在沒有修改value的情況下再次調用該方法的時候, //也第二次調用了InterpreterContext::replece $this->value=null; } }}//操作符運算式 抽象基類abstract class OperatorExpression extends Expression{ //左右運算元 protected $l_op; protected $r_op; function __construct(Expression $l_op,Expression $r_op){ $this->l_op=$l_op; $this->r_op=$r_op; } function interpret(InterpreterContext $context){ $this->l_op->interpret($context); $this->r_op->interpret($context); $result_l=$context->lookup($this->l_op); $result_r=$context->lookup($this->r_op); $this->doInterpret($context, $result_l, $result_r); } protected abstract function doInterpret(InterpreterContext $context,$result_l,$result_r);}//相等運算式class EqualsExpression extends OperatorExpression{ //計算後將結果儲存進this裡... protected function doInterpret(InterpreterContext $context,$result_l,$result_r){ $context->replace($this, $result_l==$result_r); }}//布爾或運算式class BooleanOrExpression extends OperatorExpression{ protected function doInterpret(InterpreterContext $context, $result_l, $result_r){ $context->replace($this, $result_l || $result_r); }}//布爾與運算式class BooleanAndExpression extends OperatorExpression{ protected function doInterpret(InterpreterContext $context, $result_l, $result_r){ $context->replace($this, $result_l && $result_r); }}/*$context=new InterpreterContext();$literal=new LiteralExpression("Bob");$literal->interpret($context);print $context->lookup($literal);//Bob$context=new InterpreterContext();$myvar=new VariableExpression("V","one");$myvar->interpret($context);print $context->lookup($myvar);//one$myothervar=new VariableExpression("V");$myvar->interpret($context);print $context->lookup($myvar);//one*///利用上面的代碼來檢測迷你型語言//$input equals "4" or $input equals "four"$context=new InterpreterContext();//一個沒有賦值的變數$input=new VariableExpression('input');//定義一個複雜的布爾型變數,初始化的參數被儲存在l_op,r_op裡面//注意,此時他們還沒有進行相關運算,必須等到調用布爾型變數的interpret()//之後,布爾型變數裡面的參數才會各自調用自身的interpret,形成一個調用棧...$statement=new BooleanOrExpression( new EqualsExpression($input, new LiteralExpression('four')), new EqualsExpression($input, new LiteralExpression('4')));$statement->interpret($context);print $context->lookup($statement);foreach (array('four','4','52') as $val){ $input->setValue($val); print "$val:\n"; $statement->interpret($context); if($context->lookup($statement)){ print "top marks\n"; }else{ print "dunce hat on\n\n"; }}/*four:top marks4:top marks52:dunce hat on*/ 2.策略模式 將類中許多不同操作而且是來自同一個介面的演算法,獨立起來封裝在一個新類中,主類在由分類組合或者彙總而成//Question類將由Marker彙總而成abstract class Question{ protected $prompt; protected $marker; function __construct($prompt,Marker $marker){ $this->marker=$marker; $this->prompt=$prompt; } //利用委託實現 function mark($response){ return $this->marker->mark($response); }}class TextQuestion extends Question{ //處理文本問題特有的操作}class AVQuestion extends Question{ //處理語音問題特有操作}//策略對象//將演算法部分獨立出來封裝在Marker類中....abstract class Marker{ protected $test; function __construct($test){ $this->test=$test; } abstract function mark($response);}//MarkLogic語言class MarkLogicMarker extends Marker{ protected $engine; function __construct($test){ parent::__construct($test); } function mark($response){ //類比返回true return true; }}//直接匹配class MatchMarker extends Marker{ function mark($response){ return ($this->test==$response); }}//Regexclass RegexpMarker extends Marker{ function mark($response){ return (preg_match($this->test, $response)); }}//用戶端範例程式碼$markers=array(new RegexpMarker("/f.ve/"), new MatchMarker("fivev"), new MarkLogicMarker('$input equals "five"'));foreach($markers as $marker){ print get_class($marker)."\n"; //建立一個問題,將marker執行個體傳進去 $question=new TextQuestion("How many beans make five", $marker); foreach (array("five","four") as $response){ print "\t response:$response: "; if($question->mark($response)){ print "well done\n"; }else{ print "never mind\n"; } }}/*RegexpMarker response:five: well done response:four: never mindMatchMarker response:five: never mind response:four: never mindMarkLogicMarker response:five: well done response:four: well done*/3 觀察者模式 觀察者模式的和興是把客戶元素(觀察者)從一個中心類中分離開來.當主體中有事件發生時,觀察者必須被通知到!同時觀察者和主體類不是通過寫入程式碼實現,而是通過介面組合彙總實現*問題// Login類(主體類)class Login { const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array (); // 登入操 function handleLogin($user, $pass, $ip) { $ret=false; switch (rand ( 1, 3 )) { case 1 : $this->setStatus ( self::LOGIN_ACCESS, $user, $ip ); $ret=ture; break; case 2 : $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip ); $ret=false; break; case 3 : $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip ); $ret=false; break; default: $ret=false; } //如果需要記錄IP時 Logger::logIP($user, $ip, $this->getStatus()); //如果需要把登入失敗的人的IP發送到管理員郵箱時... if(!$ret){ Notifier::mailWarning($user, $ip, $this->getStatus()); } //還需要其他功能時,比如特殊IP需要設定cookie等... //需要在這裡面一直添加... return $ret; } function setStatus($status, $user, $ip) { $this->status = array ($status,$user,$ip); } function getStatus(){ return $this->status; }}class Logger{ static function logIP($user,$ip,$status){}}class Notifier{ static function mailWarning($user,$ip,$status){}}*利用觀察者模式,使代碼改動少些....// 主體類的抽象介面interface Observable{ //附加 function attach(Observer $observer); //刪除 function detach(Observer $observer); //通知 function notify();}// Login類(主體類)class Login implements Observable{ const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $observers; private $status = array (); // 登入操作 function handleLogin($user, $pass, $ip) { $ret=false; switch (rand ( 1, 3 )) { case 1 : $this->setStatus ( self::LOGIN_ACCESS, $user, $ip ); $ret=ture; break; case 2 : $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip ); $ret=false; break; case 3 : $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip ); $ret=false; break; default: $ret=false; } //使用觀察者模式之後,如果需要增加新功能,只需要在本類中添加觀察者執行個體即可... $this->notify(); return $ret; } function setStatus($status, $user, $ip) { $this->status = array ($status,$user,$ip); } function getStatus(){ return $this->status; } function attach(Observer $observer){ $this->observers[]=$observer; } function detach(Observer $observer){ $newObserver=array(); foreach ($this->observers as $obs){ if($obs!==$observer){ $newObserver[]=$obs; } } $this->observers=$newObserver; } //通知所有觀察者 function notify(){ foreach ($this->observers as $bos){ $bos->update($this); } }}//觀察者介面interface Observer{ function update(Observable $observable);}class SecurityMonitor implements Observer{ function update(Observable $observable){ //getStatus()不是Observable介面規定的方法 $status=$observable->getStatus(); //對status的判斷也涉及到耦合問題 if($status[0]==Login::LOGIN_WRONG_PASS){ //發送郵件給管理員 print __CLASS__.":\t sending mail to sysadmin\n"; } }}$login=new Login();$login->attach(new SecurityMonitor());$login->handleLogin("coco", "123456", "127.0.0.1");//有可能輸出發送訊息到管理員 *改進後的觀察者模式//可觀察元素:主體類的基底介面interface Observable{ //附加 function attach(Observer $observer); //刪除 function detach(Observer $observer); //通知 function notify();}// Login類(主體類)class Login implements Observable{ const LOGIN_USER_UNKNOWN = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $observers; private $status = array (); // 登入操作 function handleLogin($user, $pass, $ip) { $ret=false; switch (rand ( 1, 3 )) { case 1 : $this->setStatus ( self::LOGIN_ACCESS, $user, $ip ); $ret=ture; break; case 2 : $this->setStatus ( self::LOGIN_WRONG_PASS, $user, $ip ); $ret=false; break; case 3 : $this->setStatus ( self::LOGIN_USER_UNKNOWN, $user, $ip ); $ret=false; break; default: $ret=false; } //使用觀察者模式之後,如果需要增加新功能,只需要在本類中添加觀察者執行個體即可... $this->notify(); return $ret; } function setStatus($status, $user, $ip) { $this->status = array ($status,$user,$ip); } function getStatus(){ return $this->status; } function attach(Observer $observer){ $this->observers[]=$observer; } function detach(Observer $observer){ $newObserver=array(); foreach ($this->observers as $obs){ if($obs!==$observer){ $newObserver[]=$obs; } } $this->observers=$newObserver; } //通知所有觀察者 function notify(){ foreach ($this->observers as $bos){ $bos->update($this); } }}//觀察者介面interface Observer{ function update(Observable $observable);}//Login:觀察者超類(用於解決直接在Observer中調用具體的Observable子類造成的風險)abstract class LoginObserver implements Observer{ private $login; function __construct(Login $login){ $this->login=$login; $this->login->attach($this); } //該方法在Observable的子類某些方法被調用時觸發 function update(Observable $observable){ //觸發該方法時,傳入的參數必須是Login才有效... if($this->login===$observable){ $this->doUpdate($observable); } } abstract function doUpdate(Login $login); }//改進後的觀察者能保證調用的Observable執行個體方法一定存在class SecurityMonitor extends LoginObserver{ function doUpdate(Login $login){ $status=$login->getStatus(); //對status的判斷也涉及到耦合問題 if($status[0]==Login::LOGIN_WRONG_PASS){ //發送郵件給管理員 print __CLASS__.":\t sending mail to sysadmin\n"; } }}//日常記錄class GeneralLogger extends LoginObserver{ function doUpdate(Login $login){ $status=$login->getStatus(); //添加記錄到log中 //... print __CLASS__."\t add login data to log\n"; }}//夥伴工具類class PartnershipTool extends LoginObserver{ function doUpdate(Login $login){ $status=$login->getStatus(); //檢查IP,如果匹配,則設定cookie... //... print __CLASS__."\t set cookie if IP matches a list\n"; }}//用戶端代碼有一點點改變...$login=new Login();new SecurityMonitor($login);new GeneralLogger($login);new PartnershipTool($login);$login->handleLogin("coco", "123456", "127.0.0.1");/* * 有可能輸出 *SecurityMonitor: sending mail to sysadmin *GeneralLogger add login data to log *PartnershipTool set cookie if IP matches a list **/4. 訪問者模式 當使用對象集合時,我們可能需要對結構上每一個單獨的組件應用各種操作.這樣的操作可以內建於組件本身,畢竟組件內部調用其他組件是最方便的. 但是這種方法也存在問題,因為我們並不知道所有可能需要的執行的操作.如果每增加一個操作,就在類中增加一個對於新操作的支援,類就會變得越來越臃腫.訪問者模式可以解決這個問題.//本例是基於"文明"遊戲的代碼建立而成...//*戰鬥單元類abstract class Unit{ //深度 protected $depth=0; //攻擊強度 abstract function bombardStrength(); function getComposite(){ return null; } //為訪問者模式打造的方法 function accept(ArmyVisitor $visitor){ //構建一個根據自己規則定義的方法名,然後交給visitor自身調用 $method="visit".get_class($this); $visitor->$method($this); } //用於計算Unit在對象樹中的深度 protected function setDepth($depth){ $this->depth==$depth; } function getDepth(){ return $this->depth; }}//複合抽象類別abstract class CompositeUnit extends Unit{ protected $units=array(); //為訪問者模式打造的方法 function accept(ArmyVisitor $visitor){ //構建一個根據自己規則定義的方法名,然後交給visitor自身調用 //先調用父類accept(),再遍曆調用子項目accept() parent::accept($visitor); foreach ($this->units as $thisunit){ $thisunit->accept($visitor); } } //可以不用寫bombardStrength() function getComposite(){ return $this; } //添加單元 //同時標記節點在對象樹中的深度 function addUnit(Unit $unit){ if(!empty($unit)){ if(in_array($unit, $this->units,true)){ return; } //可以用下面代碼替換in_array()函數// foreach ($this->units as $thisunit){// if($thisunit===$unit){// return;// }// } //計算好深度先... $unit->setDepth($this->depth+1); array_push($this->units, $unit); } } function removeUnit(Unit $unit){ $this->units=array_udiff($this->units, array($unit), function ($a,$b){return ($a===$b?0:1);}); } }//射手class Archer extends Unit{ function bombardStrength(){ return 4; }}//雷射塔class LaserCannonUnit extends Unit{ function bombardStrength(){ return 44; }}//軍隊:由戰鬥單元組成class Army extends CompositeUnit{ //計算總強度 function bombardStrength(){ $ret=0; foreach ($this->units as $unit){ $ret+=$unit->bombardStrength(); } return $ret; } //移動能力,防禦能力...省略}//運兵船:一個類似軍隊的單元,它具備10個戰鬥單元,有攻擊力class TroopCarrier extends CompositeUnit{ //具備和軍隊差不多的方法和屬性 function bombardStrength(){ //Do something... }}//軍隊訪問者基類abstract class ArmyVisitor{ //相關方法待會寫... //Army可能有多少種Unit,這裡就有多少個visit方法... //方法命名規則為visit+類名 //預設的visit abstract function visit(Unit $unit); function visitArcher(Archer $node){ $this->visit($node); } function visitLaserCannonUnit(LaserCannonUnit $node){ $this->visit($node); } function visitArmy(Army $node){ $this->visit($node); } function visitTroopCarrier(TroopCarrier $node){ $this->visit($node); }}//具體的Army訪問者類,用於轉存文本class TextDumpArmyVisitor extends ArmyVisitor{ private $text=""; function visit(Unit $node){ $ret=""; $pad=4*$node->getDepth(); $ret.=sprintf("%{$pad}s",""); $ret.=get_class($node).":"; $ret.="bombard: ".$node->bombardStrength()."\n"; $this->text.=$ret; } function getText(){ return $this->text; }}//用戶端執行個體代碼$army=new Army();$army->addUnit(new Archer());$army->addUnit(new LaserCannonUnit());$textdump=new TextDumpArmyVisitor();$army->accept($textdump);print $textdump->getText();/* * Army:bombard: 48 * Archer:bombard: 4 * LaserCannonUnit:bombard: 44 */5. 命令模式//命令模式//命令模式最初來源於圖形化使用者介面設計,但現在廣泛應用於公司專屬應用程式設計,特別促進了控制器(請求和分法處理)//和領域模型(應用邏輯)的分離.說得更簡單一點,命令模式有助於系統更好地進行組織,並易於擴充//Command可以設計成介面,因為它很簡單...//Commands/Command.phpabstract class Command{ abstract function execute(CommandContext $context);} require_once("Command.php");class Registry{ //一個空類... static function getAccessManager(){ return new AccessManager(); }}class AccessManager{ function login(){ return new stdClass(); } function getError(){}}class LoginCommand extends Command{ function execute(CommandContext $context){ $manager=Registry::getAccessManager(); $user=$context->get('username'); $user=$context->get('pass'); //虛構出來的空類空方法 $user_obj=$manager->login(); if(is_null($user_obj)){ $context->setError($manager->getError()); return false; } $context->addParam("user", $user); return true; }} //CommandContext類用來做任務擴增用,在這兒主要功能是傳遞資料給Command類class CommandContext{ private $params=array(); private $error=""; function __construct(){ $this->params=$_REQUEST; } function addParam($key,$val){ $this->params[$key]=$val; } function get($key){ return $this->params[$key]; } function setError($error){ $this->error=$error; } function getError(){ return $this->error; }}//用戶端代碼(用於建立命令)已經調用者代碼class CommandNotFoundException extends Exception{ }//建立命令的工廠class CommandFactory{ private static $dir="Commands"; //根據參數action,以及類檔案存放目錄$dir動態建立相應的$action+Command類 static function getCommand($action='default'){ //匹配是否出現非法字元(非字母數字底線) if(preg_match('/\W/', $action)){ throw new Exception("Illegal characters in action"); } $class=ucfirst(strtolower($action)."Command"); $file=self::$dir.DIRECTORY_SEPARATOR."{$class}.php"; if(!file_exists($file)){ throw new CommandNotFoundException("File could not be find !"); } require_once("$file"); if(!class_exists($class)){ throw new CommandNotFoundException("Class could not be find !"); } return new $class(); }}//調用者,裡麵包含一個CommandContext對象執行個體,用於存放web請求的資料class Controller{ private $context; function __construct(){ $this->context=new CommandContext(); } function getContext(){ return $this->context; } function process(){ $cmd=CommandFactory::getCommand($this->getContext()->get('action')); if(!$cmd->execute($this->context)){ //處理失敗 print "Faile in process!"; }else{ //處理成功,可以顯示相應的視圖層 print "Success in process!"; } }}$controller=new Controller();$context=$controller->getContext();$context->addParam('action', 'Login');$context->addParam('user', 'cocos');$context->addParam('pass', 'tiddles');//controller執行process方法,需要不理解command的意義.$controller->process();//Success in process