程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 七. PHP模式設計----執行及描述任務

七. PHP模式設計----執行及描述任務

編輯:關於PHP編程

七. PHP模式設計----執行及描述任務


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 marks
4:
top marks
52:
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);
    }
}
//正則表達式
class 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 mind
MatchMarker
     response:five: never mind
     response:four: never mind
MarkLogicMarker
     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.php
abstract 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











  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved