Php設計模式(三):行爲型模式part2

原文詳見:http://www.ucai.cn/blogdetail/7023?mid=1&f=5php

能夠在線運行查看效果哦!    算法

《接上文》sql

五、中介者模式(Mediator) :數據結構

      用中介對象封裝一系列的對象交互,中介使各對象不須要顯式地相互引用。相似於郵局,郵寄者和收件者不用本身跑很遠路,經過郵局就能夠。app

      好處:簡化了對象之間的關係,減小子類的生成。ide

      弊端:中介對象可能變得很是複雜,系統難以維護。性能

      應用場景:不須要顯示地創建交互。測試

代碼實現:this

<?php

/**
 * 優才網公開課示例代碼
 *
 * 中介者模式 Mediator
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */


function output($string) {
    echo    $string . "\n";
}




abstract class Mediator { // 中介者角色
    abstract public function send($message,$colleague); 
} 

abstract class Colleague { // 抽象對象
    private $_mediator = null; 
    public function __construct($mediator) { 
        $this->_mediator = $mediator; 
    } 
    public function send($message) { 
        $this->_mediator->send($message,$this); 
    } 
    abstract public function notify($message); 
} 

class ConcreteMediator extends Mediator { // 具體中介者角色
    private $_colleague1 = null; 
    private $_colleague2 = null; 
    public function send($message,$colleague) { 
        if($colleague == $this->_colleague1) { 
            $this->_colleague1->notify($message); 
        } else { 
            $this->_colleague2->notify($message); 
        } 
    }
    public function set($colleague1,$colleague2) { 
        $this->_colleague1 = $colleague1; 
        $this->_colleague2 = $colleague2; 
    } 
} 

class Colleague1 extends Colleague { // 具體對象角色
    public function notify($message) {
        output(sprintf('Colleague-1: %s', $message));
    } 
} 

class Colleague2 extends Colleague { // 具體對象角色
    public function notify($message) { 
        output(sprintf('Colleague-2: %s', $message));
    } 
} 



class Client {  
      
    public static function test(){  

        // client
        $objMediator = new ConcreteMediator(); 
        $objC1 = new Colleague1($objMediator); 
        $objC2 = new Colleague2($objMediator); 
        $objMediator->set($objC1,$objC2); 
        $objC1->send("to c2 from c1"); 
        $objC2->send("to c1 from c2"); 

    }  
      
}  
  
Client::test(); 

  

六、狀態模式(State) :spa

     對象在不一樣狀態下表現出不一樣的行爲。就像女友同樣,高興了牽你的手,不高興了遛狗。在兩種狀態下變現出不一樣的行爲。

     好處:避免if語句實用,方便增長新狀態,封裝了狀態轉換規則。

     弊端:增長系統類和對象的數量。

     應用場景:用於對象的不一樣功能的轉換。

代碼實現:

<?php

/**
 * 優才網公開課示例代碼
 *
 * 狀態模式 State
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */

function output($string) {
    echo    $string . "\n";
}

abstract class ILift {  

    //電梯的四個狀態  
    const OPENING_STATE = 1;  //門敞狀態  
    const CLOSING_STATE = 2;  //門閉狀態  
    const RUNNING_STATE = 3;  //運行狀態  
    const STOPPING_STATE = 4; //中止狀態;  
      
    //設置電梯的狀態  
    public abstract function setState($state);  
  
    //首先電梯門開啓動做  
    public abstract function open();  
  
    //電梯門有開啓,那固然也就有關閉了  
    public abstract function close();  
  
    //電梯要能上能下,跑起來  
    public abstract function run();  
  
    //電梯還要能停下來
    public abstract function stop();  

}  
  
/** 
 * 電梯的實現類  
 */   
class Lift extends ILift {  

    private $state;  
  
    public function setState($state) {  
        $this->state = $state;  
    }  

    //電梯門關閉  
    public function close() {  

        //電梯在什麼狀態下才能關閉  
        switch ($this->state) {  
            case ILift::OPENING_STATE:  //若是是則能夠關門,同時修改電梯狀態  
                $this->setState(ILift::CLOSING_STATE);  
            break;  
            case ILift::CLOSING_STATE:  //若是電梯就是關門狀態,則什麼都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::RUNNING_STATE: //若是是正在運行,門原本就是關閉的,也說明都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::STOPPING_STATE:  //若是是中止狀態,本也是關閉的,什麼也不作  
                //do nothing;  
                return ;  
            break;  
        }  

        output('Lift colse');  

    }  
  
    //電梯門開啓  
    public function open() {  
        //電梯在什麼狀態才能開啓  
        switch($this->state){  
            case ILift::OPENING_STATE: //若是已經在門敞狀態,則什麼都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::CLOSING_STATE: //如是電梯時關閉狀態,則能夠開啓  
                $this->setState(ILift::OPENING_STATE);  
            break;  
            case ILift::RUNNING_STATE: //正在運行狀態,則不能開門,什麼都不作  
            //do nothing;  
                return ;  
            break;  
            case ILift::STOPPING_STATE: //中止狀態,淡然要開門了  
                $this->setState(ILift::OPENING_STATE);  
            break;  
        }  
        output('Lift open');  
    }  
    ///電梯開始跑起來  
    public function run() {  
        switch($this->state){  
            case ILift::OPENING_STATE: //若是已經在門敞狀態,則不你能運行,什麼都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::CLOSING_STATE: //如是電梯時關閉狀態,則能夠運行  
                $this->setState(ILift::RUNNING_STATE);  
            break;  
            case ILift::RUNNING_STATE: //正在運行狀態,則什麼都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::STOPPING_STATE: //中止狀態,能夠運行  
                $this->setState(ILift::RUNNING_STATE);  
        }  
        output('Lift run');  
    }  
  
    //電梯中止  
    public function stop() {  
        switch($this->state){  
            case ILift::OPENING_STATE: //若是已經在門敞狀態,那確定要先停下來的,什麼都不作  
                //do nothing;  
                return ;  
            break;  
            case ILift::CLOSING_STATE: //如是電梯時關閉狀態,則固然能夠中止了  
                $this->setState(ILift::CLOSING_STATE);  
            break;  
            case ILift::RUNNING_STATE: //正在運行狀態,有運行固然那也就有中止了  
                $this->setState(ILift::CLOSING_STATE);  
            break;  
            case ILift::STOPPING_STATE: //中止狀態,什麼都不作  
                //do nothing;  
                return ;  
            break;  
        }  
        output('Lift stop');  
    }  
      
}  



class Client {
    
    public static function test() {

        $lift = new Lift();   
             
        //電梯的初始條件應該是中止狀態   
        $lift->setState(ILift::STOPPING_STATE);   
        //首先是電梯門開啓,人進去   
        $lift->open();   
             
        //而後電梯門關閉   
        $lift->close();   
             
        //再而後,電梯跑起來,向上或者向下   
        $lift->run();      

         //最後到達目的地,電梯挺下來   
        $lift->stop();  

    }

}

Client::test();

  

<?php

/**
 * 優才網公開課示例代碼
 *
 * 狀態模式 State
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */

function output($string) {
    echo    $string . "\n";
}

/** 
 *  
 * 定義一個電梯的接口  
 */   
abstract class LiftState{  
  
    //定義一個環境角色,也就是封裝狀態的變換引發的功能變化  
    protected  $_context;  
  
    public function setContext(Context $context){  
        $this->_context = $context;  
    }  
  
    //首先電梯門開啓動做  
    public abstract function open();  
  
    //電梯門有開啓,那固然也就有關閉了  
    public abstract function close();  
  
    //電梯要能上能下,跑起來  
    public abstract function run();  
  
    //電梯還要能停下來,停不下來那就扯淡了  
    public abstract function stop();  
  
}  
  
  
/** 
 * 環境類:定義客戶感興趣的接口。維護一個ConcreteState子類的實例,這個實例定義當前狀態。 
 */   
class Context {  
    //定義出全部的電梯狀態  
    static  $openningState = null;  
    static  $closeingState = null;  
    static  $runningState  = null;  
    static  $stoppingState = null;  
  
    public function __construct() {  
        self::$openningState = new OpenningState();  
        self::$closeingState = new ClosingState();  
        self::$runningState =  new RunningState();  
        self::$stoppingState = new StoppingState();  
  
    }  
  
    //定一個當前電梯狀態  
    private  $_liftState;  
  
    public function getLiftState() {  
        return $this->_liftState;  
    }  
  
    public function setLiftState($liftState) {  
        $this->_liftState = $liftState;  
        //把當前的環境通知到各個實現類中  
        $this->_liftState->setContext($this);  
    }  
  
  
    public function open(){  
        $this->_liftState->open();  
    }  
  
    public function close(){  
        $this->_liftState->close();  
    }  
  
    public function run(){  
        $this->_liftState->run();  
    }  
  
    public function stop(){  
        $this->_liftState->stop();  
    }  
}  
  
/** 
 * 在電梯門開啓的狀態下能作什麼事情  
 */   
class OpenningState extends LiftState {  
  
    /** 
     * 開啓固然能夠關閉了,我就想測試一下電梯門開關功能 
     * 
     */  
    public function close() {  
        //狀態修改  
        $this->_context->setLiftState(Context::$closeingState);  
        //動做委託爲CloseState來執行  
        $this->_context->getLiftState()->close();  
    }  
  
    //打開電梯門  
    public function open() {  
        output('lift open...');
    }  
    //門開着電梯就想跑,這電梯,嚇死你!  
    public function run() {  
        //do nothing;  
    }  
  
    //開門還不中止?  
    public function stop() {  
        //do nothing;  
    }  
  
}  
  
/** 
 * 電梯門關閉之後,電梯能夠作哪些事情  
 */   
class ClosingState extends LiftState {  
  
    //電梯門關閉,這是關閉狀態要實現的動做  
    public function close() {  
        output('lift close...');
  
    }  
    //電梯門關了再打開,逗你玩呢,那這個容許呀  
    public function open() {  
        $this->_context->setLiftState(Context::$openningState);  //置爲門敞狀態  
        $this->_context->getLiftState()->open();  
    }  
  
    //電梯門關了就跑,這是再正常不過了  
    public function run() {  
        $this->_context->setLiftState(Context::$runningState); //設置爲運行狀態;  
        $this->_context->getLiftState()->run();  
    }  
  
    //電梯門關着,我就不按樓層  
      
    public function stop() {  
        $this->_context->setLiftState(Context::$stoppingState);  //設置爲中止狀態;  
        $this->_context->getLiftState()->stop();  
    }  
  
}  
  
/** 
 * 電梯在運行狀態下能作哪些動做  
 */   
class RunningState extends LiftState {  
  
    //電梯門關閉?這是確定了  
    public function close() {  
        //do nothing  
    }  
  
    //運行的時候開電梯門?你瘋了!電梯不會給你開的  
    public function open() {  
        //do nothing  
    }  
  
    //這是在運行狀態下要實現的方法  
    public function run() {  
        output('lift run...');
    }  
  
    //這個事絕對是合理的,光運行不中止還有誰敢作這個電梯?!估計只有上帝了  
    public function stop() {  
        $this->_context->setLiftState(Context::$stoppingState); //環境設置爲中止狀態;  
        $this->_context->getLiftState()->stop();  
    }  
  
}  
  
  
  
/** 
 * 在中止狀態下能作什麼事情  
 */   
class StoppingState extends LiftState {  
  
    //中止狀態關門?電梯門原本就是關着的!  
    public function close() {  
        //do nothing;  
    }  
  
    //中止狀態,開門,那是要的!  
    public function open() {  
        $this->_context->setLiftState(Context::$openningState);  
        $this->_context->getLiftState()->open();  
    }  
    //中止狀態再跑起來,正常的很  
    public function run() {  
        $this->_context->setLiftState(Context::$runningState);  
        $this->_context->getLiftState()->run();  
    }  
    //中止狀態是怎麼發生的呢?固然是中止方法執行了  
    public function stop() {  
        output('lift stop...');
    }  
  
}  
  
/** 
 * 模擬電梯的動做  
 */   
class Client {  
  
    public static function test() {  
        $context = new Context();  
        $context->setLiftState(new ClosingState());  
  
        $context->open();  
        $context->close();  
        $context->run();  
        $context->stop();  
    }  
}  

Client::test();  

 

七、職責鏈模式 (Chain of Responsibility):

      多個對象有機會處理請求,爲請求發送者和接收者解耦。就像銀行裏的取款機,無論那一臺均可以取到錢。

      好處:簡單化對象隱藏鏈結構,便於添加新職責節點。

      弊端:請求可能沒有接受者,或者被多個接收者調用,性能下降。

      應用場景:處理多種請求。

代碼實現:

 

<?php

/**
 * 優才網公開課示例代碼
 *
 * 職責鏈模式 Chain of Responsibility
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */

function output($string) {
    echo    $string . "\n";
}

/** 
 * 加入在公司裏,若是你的請假時間小於0.5天,那麼只須要向leader打聲招呼就OK了。 
  若是0.5<=請假天數<=3天,須要先leader打聲招呼,而後部門經理簽字。 
  若是3<請假天數,須要先leader打聲招呼,而後到部門經理簽字,最後總經經理確認簽字, 
    若是請假天數超過10天,是任何人都不能批准的。
 */ 

  
/** 
 * 抽象處理者角色(Handler:Approver):定義一個處理請求的接口,和一個後繼鏈接(可選) 
 * 
 */  
abstract class Handler 
{  

    protected $_handler = null;  
    protected $_handlerName = null;  
      
    public function setSuccessor($handler)  
    {  
        $this->_handler = $handler;  
    }  
      
    protected  function _success($request)  
    {  
        output(sprintf("%s's request was passed", $request->getName())); 
        return true;  
    }  
    abstract function handleRequest($request);  
}  

/** 
 * 具體處理者角色(ConcreteHandler:President):處理它所負責的請求,能夠訪問後繼者,若是能夠處理請求則處理,不然將該請求轉給他的後繼者。 
 * 
 */  
class ConcreteHandlerLeader extends Handler  
{  
    function __construct($handlerName){  
        $this->_handlerName = $handlerName;  
    }  
    public function handleRequest($request)  
    {  
        if($request->getDay() < 0.5) {  
            output(sprintf('%s was told', $this->_handlerName));       // 已經跟leader招呼了
            return $this->_success($request);  
        }   
        if ($this->_handler instanceof Handler) {  
            return $this->_handler->handleRequest($request);  
        }  
    }  
}  
/** 
 * Manager 
 * 
 */  
class ConcreteHandlerManager extends Handler  
{  
    function __construct($handlerName){  
        $this->_handlerName = $handlerName;  
    }  
      
    public function handleRequest($request)  
    {  
        if(0.5 <= $request->getDay() && $request->getDay()<=3) {  
            output(sprintf('%s signed', $this->_handlerName));       // 部門經理簽字
            return $this->_success($request);  
        }   
        if ($this->_handler instanceof Handler) {  
            return $this->_handler->handleRequest($request);  
        }  
    }  

}  

class ConcreteHandlerGeneralManager extends Handler  
{  
    function __construct($handlerName){  
        $this->_handlerName = $handlerName;  
    }  
      
    public function handleRequest($request)  
    {  
        if(3 < $request->getDay() && $request->getDay() < 10){  
            output(sprintf('%s signed', $this->_handlerName));       // 總經理簽字
            return $this->_success($request);  
        }  
        if ($this->_handler instanceof Handler) {  
            return $this->_handler->handleRequest($request);  
        } else {
            output(sprintf('no one can approve request more than 10 days'));
        }
    }  

}  

/** 
 * 請假申請 
 * 
 */  
class Request  
{  
    private $_name;  
    private $_day;  
    private $_reason;  
  
    function __construct($name= '', $day= 0, $reason = ''){  
        $this->_name = $name;  
        $this->_day = $day;  
        $this->_reason = $reason;  
    }  
      
    public function setName($name){  
        $this->_name = $name;  
    }  

    public function getName(){  
        return  $this->_name;  
    }  
      
    public function setDay($day){  
        $this->_day = $day;  
    }  

    public function getDay(){  
        return  $this->_day ;  
    }  
      
    public function setReason($reason ){  
         $this->_reason = $reason;  
    }  

    public function getReason( ){  
        return  $this->_reason;  
    }  
}  
  
  
class Client {  
      
    public static function test(){  
          
        $leader = new ConcreteHandlerLeader('leader');  
        $manager = new ConcreteHandlerManager('manager');  
        $generalManager = new ConcreteHandlerGeneralManager('generalManager');  
          
        //請求實例  
        $request = new Request('ucai',4,'休息');  
          
        $leader->setSuccessor($manager);  
        $manager->setSuccessor($generalManager);  
        $result =  $leader->handleRequest($request);  
    }  
      
}  
  
Client::test(); 

  

八、策略模式(Strategy) :

      定義一系列算法,把每個算法封裝起來,而且使它們可相互替換。就像籃球隊裏的球員,場上的和場下休息的。教練可讓場上的下來,也可讓場下的上陣。

      好處:定義可重用的一系列算法和行爲,而且消除了if else語句。

      弊端:調用端必須知道全部策略類。

      應用場景:用於對象間的替換。

代碼實現:

<?php

/**
 * 優才網公開課示例代碼
 *
 * 策略模式 Strategy
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */


function output($string) {
    echo    $string . "\n";
}

//策略基類接口

interface IStrategy {
    public function OnTheWay();
}

class WalkStrategy implements IStrategy {
    public function OnTheWay() {
        output( '在路上步行');
    }
}

class RideBickStrategy implements IStrategy {
    public function OnTheWay() {
        output( '在路上騎自行車');
    }
}

class CarStrategy implements IStrategy {
    public function OnTheWay() {
        output( '在路上開車');
    }
}

//選擇策略類Context
class Context {
    public function find($strategy) {
        $strategy->OnTheWay();
    }
}

class Client {  
      
    public static function test(){  

        $travel = new Context();
        $travel->find(new WalkStrategy());
        $travel->find(new RideBickStrategy());
        $travel->find(new CarStrategy());

    }  
      
}  
  
Client::test(); 

  

  • 已知模式

一、備忘錄模式(Memento):

      保存對象在一時刻的狀態。親,還記得「老師來了記得叫我一下」的同桌的他嗎?

      好處:給用戶提供了一種能夠恢復狀態的機制。

      弊端:消耗資源。

      應用場景:用於須要保存的數據

代碼實現:

<?php

/**
 * 優才網公開課示例代碼
 *
 * 備忘錄模式 Memento
 *
 * @author 優才網全棧工程師教研組
 * @see http://www.ucai.cn
 */

function output($string) {
    echo    $string . "\n";
}


class Originator { // 發起人(Originator)角色
    private $_state;
    public function __construct() {
        $this->_state = '';
    }
    public function createMemento() { // 建立備忘錄
        return new Memento($this->_state);
    }
    public function restoreMemento(Memento $memento) { // 將發起人恢復到備忘錄對象記錄的狀態上
        $this->_state = $memento->getState();
    }
    public function setState($state) { $this->_state = $state; } 
    public function getState() { return $this->_state; }
    public function showState() {
        output($this->_state);
    }

}

class Memento { // 備忘錄(Memento)角色 
    private $_state;
    public function __construct($state) {
        $this->setState($state);
    }
    public function getState() { return $this->_state; } 
    public function setState($state) { $this->_state = $state;}
}

class Caretaker { // 負責人(Caretaker)角色 
    private $_memento;
    public function getMemento() { return $this->_memento; } 
    public function setMemento(Memento $memento) { $this->_memento = $memento; }
}

class Client {  
      
    public static function test(){  

        $org = new Originator();
        $org->setState('open');
        $org->showState();

        /* 建立備忘 */
        $memento = $org->createMemento();

        /* 經過Caretaker保存此備忘 */
        $caretaker = new Caretaker();
        $caretaker->setMemento($memento);

        /* 改變目標對象的狀態 */
        $org->setState('close');
        $org->showState();

        /* 還原操做 */
        $org->restoreMemento($caretaker->getMemento());
        $org->showState();

    }  
      
}  
  
Client::test(); 


return;


try {

    $db->beginTransaction();

    $succ   = $db->exec($sql_1);
    if (!$succ) {
        throw new Exception('SQL 1 update failed');
    }

    $succ   = $db->exec($sql_2);
    if (!$succ) {
        throw new Exception('SQL 2 update failed');
    }

    $succ   = $db->exec($sql_3);
    if (!$succ) {
        throw new Exception('SQL 3 update failed');
    }

    $db->commit();

} catch (Exception $exp) {

    $db->rollBack();

}

  

  • 深度模式

一、解釋器模式(Interpreter):

       定義語言的文法,並創建一個解釋器解釋該語言中的句子。每一個用過字典的童鞋都懂滴。

       好處:可擴展性比較好,靈活性大。

       弊端:可能難以維護複雜的文法。

       應用場景:用於成對或者一對多的需求中。

二、訪問者模式(Visitor):

      封裝某些用於做用於某種數據結構中各元素的操做,能夠在不改變數據結構的前提下定義做用於這些元素的新操做。如銀行排號機。

      好處:將相關的事物集中到一個訪問者對象中。

      弊端:增長新數據結構很困難。

      應用場景:排隊,排號。

3、總結

      本篇介紹了行爲型模式,行爲模式涉及到算法和對象職責間的分配,行爲類模式採用繼承機制在類間分派行爲,Template Method和Interpreter是類行爲模式。行爲對象模式使用對象複合而不是繼承,一些行爲

對象模式描述了一組相互對等的對象如何相互協做以完成其中任何一個對象都單獨沒法完成的任務,如Mediator在對象間引入一個mediator對象提供了鬆耦合所需的間接性;Chain of Responsibility提供了更鬆的耦

合,它經過一條候選對象鏈隱式的向一個對象發鬆請求,能夠運行時刻決定哪些候選者參與到鏈中;Observer定義並保持了對象間的依賴關係;其它的行爲對象模式常將行爲封裝封裝在一個對象中,並將請求指派給

它,Strategy模式將算法封裝在對象中,這樣能夠方面的改變和指定一個對象所使用的算法;Command模式將請求封裝在對象中,這樣它就能夠做爲參數來傳遞,已能夠存儲在歷史列表中或以其它方式使用;State

模式封裝一個對象的狀態,使得當這個對象的狀態對象變化時,該對象可改變它的行爲;Visitor模式封裝分佈於多個類之間的行爲;而Iterator模式則抽象了訪問和遍歷一個集合中對象的方式。

相關文章
相關標籤/搜索