返璞归真:面向过程的装饰模式实现
本文可以看做是Web框架审美观一文的延续,在那篇文章里,我阐述了如何用面向对象实现装饰模式,不过鉴于PHP的本质就是面向过程的,让我对纯粹的OOP有些拿不定主意,于是本文便走向另一个极端,准备阐述一下如何用面向过程实现装饰模式。
废话少说,直接贴代码(代码仅在PHP5.3以上版本有效,用到了header_remove函数),大概涉及以下几个文件:
bootstrap.php:
01 function execute_action($name = null)
02 {
03 static $action;
04 static $wrappers;
05
06 if ($name !== null) {
07 $action = $name;
08 }
09
10 if ($wrappers === null) {
11 $config = include \\\'config.php\\\';
12 $wrappers = $config[$action];
13 }
14
15 if (list($wrapper, $param) = each($wrappers)) {
16 extract($param);
17 array_shift($wrappers);
18
19 return include $wrapper . \\\'_wrapper.php\\\';
20 }
21
22 ob_start();
23
24 include $action . \\\'_action.php\\\';
25
26 return ob_get_clean();
27 }
28
29 echo execute_action(\\\'foo\\\');
说明:这里的static变量是面向过程装饰模式的实现关键,它会控制程序依次执行所有的装饰器和动作。
config.php:
01 return array(
02 \\\'foo\\\' => array(
03 \\\'bar\\\' => array(\\\'param_a\\\' => \\\'[a]\\\', \\\'param_b\\\' => \\\'[b]\\\'),
04 // other wrappers
05 ),
06 // other actions
07 );
说明:配置文件使用的是直接return的方式,在include的时候可以接收到参数,里面可以针对动作设置装饰器,并且可以设置装饰器的参数。
bar_wrapper.php:
01 $result = execute_action();
02
03 header_remove(\\\'Location\\\');
04
05 return $result . $param_a . $param_b;
说明:在装饰器里可以修改响应头,还可以修改响应内容,注意结果是return的,不是echo的。
foo_action.php:
01 header(\\\'Location: http://www.baidu.com/\\\');
02 // exit; or return;
03
04 echo \\\'hello, world.\\\';
说明:在动作里没有任何特殊性,就是页面控制器风格,这样可以兼容最一般的PHP编程风格。
把以上文件保存到根目录,然后浏览bootstrap.php就可以看到效果:hello, world.[a][b]。全部代码都是面向过程的,和面向对象不沾边,对PHP这样的瞬态执行的语言来说,这样可以实现效率最大化。再看细节,虽然我们在动作文件里设定了跳转,但是在装饰器文件里可以删除这个响应头,从而达到透明修改的装饰目的,装饰器对动作的修改没有任何侵入性设计。以此为基础,可以实现一个相当灵活的Web框架(VC of MVC),既能保证效率,又可以兼顾扩展性。不过这样的设计也有一些弱点,比如说可测试性会有点麻烦,另外,没有了OOP,显得有些土气(如果你这样认为的话)。
注意:由于在操作action和wrapper的时候,使用的是include方式,所以可能会带来变量污染的问题,一般来说,只要稍加注意不会出大问题,不过如果有完美主义倾向,可以使用PHP5.3新加入的闭包特色来规避这类问题:function() use(...) { include ... };,但效率会略微降低一点。
补充:肯定会有人鄙视这样的面向过程风格的代码,其实大可不必,我记得以前有好事者曾经问过CPP之父一个尖锐的问题:和Ruby这样百分百面向对象的语言相比,CPP是不是显得不够好?CPP之父回答道:我不认为百分百面向对象是优点!对于PHP来说,我也认为百分百面向对象不可取,当然百分百面向过程也不可取,在我看来更合理的方式是:如果按MVC算的话,M应该是面向对象的,而VC则应该是面向过程的,这样可以达到一个合理的平衡点。
转自:http://hi.baidu.com/thinkinginlamp/blog/item/28888d10f17a780d213f2e95.html
- 代理(Proxy)和委派(Delegate)的区别 - 2010年04月11日 20:04
- win7+iis+php+fastcgi安装 - 11月02日 13:57
- 在win2003下使用iis6+fastcgi+php+mysql - 2011年02月17日 01:02
- eAccelerator for php 5.3.4 on windows at vc6 - 2011年01月06日 22:49
- powerdesigner 12 逆向工程mysql 5.0 数据库 - 2010年05月26日 17:59
- 记录,今天搞了我大半天,扑街的php+win7 - 2010年04月20日 18:07
- PC 服务器的 RAS 能力 - 2010年04月11日 20:04
- 多IDC的数据分布设计(二) - 2010年04月11日 20:37
- 股指期货,玩法多少种? - 2010年04月11日 20:31
- 10个免费的图表生成代码 - 2010年04月04日 23:51
