标题: [原创]用PHP实现装饰或包装模式
trooman
新手上路
Rank: 1



UID 683
精华 0
积分 0
帖子 5
翻译 0
原创 0
阅读权限 10
注册 2007-12-25
状态 离线
发表于 2008-3-7 11:24  资料  短消息  加为好友 
[原创]用PHP实现装饰或包装模式

老王的BLOG上有篇帖子”PHP实现透明化事务处理“,谈到了装饰模式(包装模式),感觉受到很大启发,

经过一番胡思乱想后,最终结合PHP的特点,用以下方式实现可能最好,这个设计完全是独自想到的,没参考任何先人的思想,难免有不足之处,欢迎指正!

<?php

class FooAction {
    public function execute() {
         echo "<br />\r\n";
         echo "FooAction::execute()<br />\r\n";
         echo "<br />\r\n";
    }
}

abstract class WrapperBehavior {
        abstract public function before();
        abstract public function after();
       
        public function getName() {
                return get_class($this);
        }
}

class Authorization extends WrapperBehavior {
        public function before() {
                echo "Authorization begin<br />\r\n";
        }
       
        public function after() {
                echo "Authorization end<br />\r\n";
        }
}

class Transaction extends WrapperBehavior {
        public function before() {
                 echo "Transaction begin<br />\r\n";
        }
       
        public function after() {
                echo "Transaction end<br />\r\n";
        }
}

class Wrapper {
        protected $_srcObj = null;
        protected $_wrapperBehaviors = array();
       
        public function __construct($obj) {
                $this->_srcObj = $obj;
        }
       
        public function add($srcMethod, $wrapperBehavior) {
                $this->_wrapperBehaviors[$srcMethod][$wrapperBehavior->getName()] = $wrapperBehavior;
        }
       
        public function __call($method, $args) {
                if (! method_exists($this->_srcObj, $method)) {
                        throw new Exception("The method {$method} not exists");
                }
               
                //before
                foreach (array_reverse($this->_wrapperBehaviors[$method]) as $behavior) {
                        $behavior->before();
                }
               
                call_user_func_array(array(&$this->_srcObj, $method), $args); //用反射可能更好
               
                //end
                foreach ($this->_wrapperBehaviors[$method] as $behavior) {
                        $behavior->after();
                }
        }
}


$action = new FooAction();
$wrapper = new Wrapper($action);
$wrapper->add('execute', new Transaction());
$wrapper->add('execute', new Authorization());
$wrapper->execute();

顶部
trooman
新手上路
Rank: 1



UID 683
精华 0
积分 0
帖子 5
翻译 0
原创 0
阅读权限 10
注册 2007-12-25
状态 离线
发表于 2008-3-7 16:59  资料  短消息  加为好友 
上面的实现未考虑异常处理,下面增加了异常处理,改进后的代码如下:

<?php

class FooAction {
    public function execute($exception = false) {
        echo "<br />\r\n";
        echo "FooAction::execute()<br />\r\n";
        echo "<br />\r\n";
               
                if ($exception) {
                        throw new Exception('haha');
                }
    }
}

abstract class WrapperBehavior {
        protected $_currentException = null;
        abstract public function before();
        abstract public function after();
       
        public function getName() {
                return get_class($this);
        }
       
        public function setCurrentException($exception)
        {
                $this->_currentException = $exception;
        }
       
        public function hasException()
        {
                return $this->_currentException ? true : false;
        }
}

class Authorization extends WrapperBehavior {
        public function before() {
                echo "Authorization begin<br />\r\n";
        }
       
        public function after() {
                echo "Authorization end<br />\r\n";
        }
}

class Transaction extends WrapperBehavior {
        public function before() {
                 echo "Transaction begin<br />\r\n";
        }
       
        public function after() {
                if ($this->hasException())
                {
                        echo "Transaction rollback<br />\r\n";
                        //throw $this->_currentException;
                        echo $this->_currentException->getMessage();
                        exit;
                }
                echo "Transaction end<br />\r\n";
        }
}

class Wrapper {
        protected $_srcObj = null;
        protected $_currentException = null;
        protected $_wrapperBehaviors = array();
       
        public function __construct($obj) {
                $this->_srcObj = $obj;
        }
       
        public function add($srcMethod, $wrapperBehavior) {
                $this->_wrapperBehaviors[$srcMethod][$wrapperBehavior->getName()] = $wrapperBehavior;
        }
       
        public function __call($method, $args) {
                if (! method_exists($this->_srcObj, $method)) {
                        throw new Exception("The method {$method} not exists");
                }
               
                //before
                foreach (array_reverse($this->_wrapperBehaviors[$method]) as $behavior) {
                        $behavior->before();
                }
               
                try {
                        call_user_func_array(array(&$this->_srcObj, $method), $args); //用反射可能更好
                } catch (Exception $e) {
                        $this->_currentException = $e;
                }
               
                //end
                foreach ($this->_wrapperBehaviors[$method] as $behavior) {
                        if ($this->_currentException) {
                                $behavior->setCurrentException($this->_currentException);
                        }
                        $behavior->after();
                }
        }
}


$action = new FooAction();
$wrapper = new Wrapper($action);
$wrapper->add('execute', new Transaction());
$wrapper->add('execute', new Authorization());
$wrapper->execute(true);

顶部
mayongzhan
PHPEye Developer
Rank: 8Rank: 8


UID 136
精华 2
积分 20
帖子 39
翻译 18
原创 1
阅读权限 1
注册 2007-6-30
状态 离线
发表于 2008-3-13 23:05  资料  短消息  加为好友 
从老王的blog上跟过来看一下.不错!





顶部
 


PHPEye社区--LAMP开源技术社区


当前时区 GMT+8, 现在时间是 2008-7-21 02:23

    Powered by Discuz! 5.5.0  © 2001-2007 Comsenz Inc.
Processed in 0.016268 second(s), 6 queries , Gzip enabled

清除 Cookies - 联系我们 - PHPEye开源社区 - Archiver - WAP