
2008-3-7 11:24
trooman
[原创]用PHP实现装饰或包装模式
老王的BLOG上有篇帖子”PHP实现透明化事务处理“,谈到了装饰模式(包装模式),感觉受到很大启发,:lol
经过一番胡思乱想后,最终结合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();
2008-3-7 16:59
trooman
上面的实现未考虑异常处理,下面增加了异常处理,改进后的代码如下:
<?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);
2008-3-13 23:05
mayongzhan
从老王的blog上跟过来看一下.不错!
页:
[1]
Powered by Discuz! Archiver 5.5.0
© 2001-2006 Comsenz Inc.