PHP、Python和Javascript的装饰器模式对比


Posted in PHP onFebruary 03, 2015

修饰模式(Decorator Pattern),又叫装饰者模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。装饰模式非常适用于灵活扩展对象的功能,下面是装饰模式的UML图:

PHP、Python和Javascript的装饰器模式对比

例如,有一个技术论坛,用户通过留言进行沟通,由于刚开始论坛里都是熟人,几乎都不需要对留言的内容作出审核,接收留言的页面可以是这样:

class SaveMsg(){
 private $msg;
 public function __construct($msg){
 $this->msg=$msg;
 }
 public function __store(){
 //存入数据库
 }
}

后来,随着论坛逐渐出名,就有一些人在上面发链接,就需要对含有链接的消息进行过滤,论坛进一步发展,发现除开发垃圾链接的外,还有很多无用的灌水,到后来可能还有攻击等等各种不正常的帖子,所以对论坛帖子的管理,可以单独抽象出一个类进行管理,当需要扩充过滤规则时,可以进行动态扩充。

//基类
abstract class Filter{
 abstract public function isForbid();
}
//基础过滤类
class MsgFilter extends Filter{
 public $content;
 public function __construct($msg){
 $this->content=$msg;
 }
 public function isForbid(){
 if(preg_match("/https?/i",$this->content)){
 return [true,"Not Allowed Urls"];
 }else{
 return [false];
 }
 }
}
//装饰器,用来扩充功能
abstract class FilterDecorator extends Filter{
 protected $obj;
 public function __construct(Filter $obj){
 $this->obj=$obj;
 }
}
//新过滤器,判断是否重复发帖
class repeat extends FilterDecorator{
 public function isForbid(){
 if($this->obj->isForbid()[0] === true){
 //判定是否包含url
 return $this->obj->isForbid();
 }else if($this->obj->content == "this is a test"){
 //判定是否重复发帖
 return [true,"Repeat Posts"];
 }else{
 return [false];
 }
 }
}
$test = new MsgFilter("httpsfdjoafdsajof");
print_r($test->isForbid());//被禁止
$test2 = new repeat(new MsgFilter("this is a test"));
print_r($test2->isForbid());//被禁止

在python中,不存在抽象类和方法,实现就更加简单:

#!/usr/bin/env python
class Filter():
  pass
class MsgFilter(Filter):
  def __init__(self,msg):
    self.content=msg
  def isForbid(self):
    if('http' in self.content):
      return [True,"Not Allowed Urls"]
    else:
      return [False]
class FilterDecorator(Filter):
  def __init__(self,obj):
    self._obj=obj
class Repeat(FilterDecorator):
  def isForbid(self):
    if self._obj.isForbid()[0]:
      return self._obj.isForbid()
    elif self._obj.content == 'this is a test':
      return [True,"Repeat Posts"];
    else:
      return [False]
test = MsgFilter("this is a content have http urls")
print test.isForbid()
test2 = Repeat(MsgFilter('this is a test'))
print test2.isForbid()

Javascript中,没有严格的类,所有继承都基于原型,理解起来会稍费功夫:

function MsgFilter(msg){
 this.content=msg;
 this.isForbid=function(){
 if(this.content.match(/http/g)){
 return [true,"Not Allowed Urls"];
 }else {
 return [false];
 }
 }
}
function Repeat(obj){
 var _obj=obj;
 this.isForbid=function(){
 if(_obj.isForbid[0] === true){
 return _obj.isForbid();
 }else if(_obj.content=='this is a test'){
 return [true,"Repeat Posts"];
 }else{
 return [false];
 }
 }
}
var test = new MsgFilter("his is a content have http urls");
console.log(test.isForbid());
var test2 = new Repeat(new MsgFilter("this is a test"));
console.log(test2.isForbid());

由于Javascript缺少类的特性,继承对于它来说就显得有点鸡肋了,上面的代码看起来更像是对两个函数的处理, 在python中,有更加简单的添加装饰器的方法,直接通过”@”给函数自动添加装饰器,达到扩展功能的目的,如:

def Decorator(F):
  def newF(age):
    print "You Are Calling",F.__name__
    F(age)
  return newF
@Decorator
#通过@给函数showAge添加装饰器Decorator
def showAge(age):
  print "hello , i am %d years old"%age
showAge(10)

装饰模式的目的是解决动态扩展功能的难题,装饰模式的本质是对对象的灵活处理,理解装饰模式,不仅能深入了解面向对象的程序设计,更能提高编程的思维能力。

PHP 相关文章推荐
fleaphp rolesNameField bug解决方法
Apr 23 PHP
PHP 多维数组的排序问题 根据二维数组中某个项排序
Nov 09 PHP
php错误、异常处理机制(补充)
May 07 PHP
PHP中include与require使用方法区别详解
Oct 19 PHP
PHP输出当前进程所有变量/常量/模块/函数/类的示例
Nov 07 PHP
PHP数字字符串左侧补0、字符串填充和自动补齐的几种方法
May 10 PHP
yii的CURD操作实例详解
Dec 04 PHP
php中adodbzip类实例
Dec 08 PHP
php校验表单检测字段是否为空的方法
Mar 20 PHP
php函数mkdir实现递归创建层级目录
Oct 27 PHP
用PHP去掉文件头的Unicode签名(BOM)方法
Jun 22 PHP
php设计模式之代理模式分析【星际争霸游戏案例】
Mar 23 PHP
php对象在内存中的存在形式分析
Feb 03 #PHP
浅析THINKPHP的addAll支持的最大数据量
Feb 03 #PHP
php格式化金额函数分享
Feb 02 #PHP
php可应用于面包屑导航的迭代寻找家谱树实现方法
Feb 02 #PHP
php生成唯一的订单函数分享
Feb 02 #PHP
php数组去除空值函数分享
Feb 02 #PHP
php截取字符串函数分享
Feb 02 #PHP
You might like
实现树状结构的两种方法
2006/10/09 PHP
php.ini中文版
2006/10/09 PHP
PHP中HTTP方式下的Gzip压缩传输方法举偶
2007/02/15 PHP
php递归法读取目录及文件的方法
2015/01/30 PHP
超级强大的表单验证
2006/06/26 Javascript
JavaScript中各种编码解码函数的区别和注意事项
2010/08/19 Javascript
非主流的textarea自增长实现js代码
2011/12/20 Javascript
javaScript矢量图表库-gRaphael几行代码实现精美的条形图/饼图/点图/曲线图
2013/01/09 Javascript
不提示直接关闭网页窗口的JS示例代码
2013/12/17 Javascript
jQuery常用操作方法及常用函数总结
2014/06/19 Javascript
jQuery Timelinr实现垂直水平时间轴插件(附源码下载)
2016/02/16 Javascript
Node.js Sequelize如何实现数据库的读写分离
2016/10/23 Javascript
jQuery使用zTree插件实现可拖拽的树示例
2017/09/23 jQuery
基于vue-ssr服务端渲染入门详解
2018/01/08 Javascript
vue单页缓存存在的问题及解决方案(小结)
2018/09/25 Javascript
vue-better-scroll 的使用实例代码详解
2018/12/03 Javascript
node中使用es6/7/8(支持性与性能)
2019/03/28 Javascript
vue数据初始化initState的实例详解
2019/04/11 Javascript
JavaScript简单编程实例学习
2020/02/14 Javascript
通过实例解析json与jsonp原理及使用方法
2020/09/27 Javascript
使用Python进行目录的对比方法
2018/11/01 Python
对Python中的条件判断、循环以及循环的终止方法详解
2019/02/08 Python
Python使用LDAP做用户认证的方法
2019/06/20 Python
python如何实现不可变字典inmutabledict
2020/01/08 Python
python3中关于excel追加写入格式被覆盖问题(实例代码)
2020/01/10 Python
python json load json 数据后出现乱序的解决方案
2020/02/27 Python
CSS3 实现弹幕的示例代码
2017/08/07 HTML / CSS
Giglio英国站:意大利奢侈品购物网
2018/03/06 全球购物
乐高官方旗舰店:LEGO积木玩具
2019/04/06 全球购物
毕业生个人求职信范例分享
2013/12/17 职场文书
司法局群众路线教育实践活动整改措施
2014/09/17 职场文书
帮你提高开发效率的JavaScript20个技巧
2021/06/18 Javascript
mysql脏页是什么
2021/07/26 MySQL
Java对文件的读写操作方法
2022/04/29 Java/Android
mysql查找连续出现n次以上的数字
2022/05/11 MySQL
Hive HQL支持2种查询语句风格
2022/06/25 数据库