老生常谈PHP面向对象之解释器模式


Posted in PHP onMay 17, 2017

最近在看 “深入PHP面向对象模式与实践” ,学习书中的内容后瞬间觉得自己有点高大上了,哈 ! 其实还是个菜B。相信也会有新手朋友在看这本(我自己也是新手),对书中我个人认为比较难的内容的学习心得就想拿出来分享和交流,1是希望对自己所学知识能够起到巩固和加深理解的作用 2是希望对看到本文且感兴趣的新手朋友一些帮助。

这部分内容看了好几遍了代码也跟着敲了几遍,估计本文想要实现的功能大概就是用户在web页面上输入一些内容,然后通过后台程序解析后进行回复(感觉就是在废话)。例如我在前台web页面输入框里输入:

$input = "4";
$input equals "4" or $input equals "four";

然后提交,系统就会回复类似 “条件成立” 或者 “条件不成立”的结果(有点类似直接在前台写代码并运行,后台解析后会返回一个结果。原书中虽然没有讲解整个前台输入到后台解析的过程但我猜这个后台解析应该还有一个使用正则表达式提取类似上面2行代码中关键字的过程)

上面这二行代码虽然是作者发明的语言,但根据字面含义也不难理解,第一行是定义一个变量并赋值,第二行是对变量进行一个判断(变量等于4或者等于four)。

废话不多说来看看这个模式定义的这几个类 (类图请自行看原文):

一、interpreterContext 这个类就像一个容器 主要是用来存放和获取需要进行比较的值和比较的结果的,例如上述代码中的4, four,和比较结果 “true”或“false”,保存的形式是数组即类的属性$expressionstore,代码如下:

class InterpreterContext{
  private $expressionstore = array(); //存放比较的值和结果
  
  function replace(Expression $exp,$value){// 设置值
    $this->expressionstore[$exp->getKey()] = $value;
  }
  
  function lookup(Expression $exp){//获取值
    return $this->expressionstore[$exp->getKey()];
  }
}

这个类就像一个工具,供其他类来使用(它和其他类不存在继承、组合或聚合的关系)。

二、Expression 这是一个表达式的抽象类,定义了抽象方法interpret() 和方法getKey()

代码如下:

abstract class Expression {
  private static $keycount = 0;//计数用的
  private $key;//存放一个唯一值


  //主要实现将前台获取到的数据存放到上述InterpreterContext类中的功能,看到下面的内容就会发现继承他的类调用了InterpreterContext类的replace()方法
  abstract function interpret (InterpreterContext $context); 

 //获取一个唯一值  
  function getKey(){ 
    if(!isset($this->key)){
      self::$keycount++;
      $this->key= self::$keycount;
    }
    return $this->key;
  }
}

下面将要讲到的类都将继承这个类,并且他和OperatorExpression(操作符表达式抽象类)是一个组合的关系,也就是说OperatorExpression在初始化时可以包含所有继承了Expression的子类(这也是本书一直在强调的要面向接口编程,这个Expression就是个接口,利用这个接口可以实现多态,不知道自己装B说的对不对,哈! 具体可以在看看原书的类图)

三、LiteralExpression 文字表达式类,作用就是将一个字符串保存到InterpreterContext这个小容器里,保存成一个索引数组,例如保存开头那二句自创代码中的 4 或者 four

代码如下:

class LiteralExpression extends Expression{
  private $value;  
  function __construct ($value){//初始化时传入要保存的值
    $this->value= $value;
  }
  function interpret(InterpreterContext $context){//调用InterpreterContext类的replace()将$value保存到InterpreterContext这个小容器里
    $context->replace($this,$this->value);
  }
}

四、VariableExpression 变量表达式类,和上面类的作用是一样的只不过数据将被保存成关联数组,关联数组中的健是变量名,值呢就是变量的值,例如开头二句中的变量"input" 和值 "4",

代码如下:

class VariableExpression extends Expression{
  private $name;//变量名
  private $val;//变量值
  
  function __construct ($name,$val=null){
    $this->name = $name;
    $this->val = $val;
  }
  
  function interpret(InterpreterContext $context){
    if(!is_null($this->val)){
      $context->replace($this,$this->val);
      $this->val = null;
    }
  }
  
  function setValue($value){//用于设置变量的值
    $this->val = $value;
  }
  
  function getKey(){//这个复写了父类的getKey()方法,在小容器InterpreterContext的lookup()方法调用这个类的实例的getKey()方法时 它将返回一个字符串(即变量名)而不是数字索引
    return $this->name;
  }
}

五、OperatorExpression 操作符表达式抽象基类,此类继承且组合了Expression抽象基类,实现的interpret()方法主要保存表达式的计算结果

代码如下:

abstract class OperatorExpression extends Expression{
protected $l_op;//表达式左边的值
protected $r_op;//表达式右边的值

function __construct (Expression $l_op,Expression $r_op){//初始化时可组合继承了Expression类的子类实例
$this->l_op = $l_op;
$this->r_op = $r_op;
}

function interpret(InterpreterContext $context){  //主要用于保存表达试的结果(保存到InterpreterContext 类的实例中)
$this->l_op->interpret($context);//将Expression子类实例的值或计算结果保存到InterpreterContext 类的实例中
$this->r_op->interpret($context);
$result_l = $context->lookup($this->l_op);//获取上一步的值或计算结果
$result_r = $context->lookup($this->r_op);
$this->doInterpret($context,$result_l,$result_r);//具体的比较运算由继承的子类来实现
}

protected abstract function doInterpret(InterpreterContext $context,$result_l,$result_r);

}

六、EqualsExpression、BooleanOrExpression、BooleanAndExpression,分别为继承了OperatorExpression 抽象基类的相等表达式、或表达式、与表达式只有一个方法doInterpret()内部调用了InterpreterContext类的replace()方法将表达式的计算结果保存到InterpreterContext类的实例中

代码如下:

//相等表达式
class EqualsExpression extends OperatorExpression {
protected function doInterpret(InterpreterContext $context,$result_l,$result_r){
$context->replace($this,$result_l == $result_r);
}
}

//或表达式
class BooleanOrExpression extends OperatorExpression{
protected function doInterpret(InterpreterContext $context,$result_l,$result_r){
$context->replace($this,$result_l || $result_r);
}
}


//与表达式
class BooleanAndExpression extends OperatorExpression{
protected function doInterpret(InterpreterContext $context,$result_l,$result_r){
$context->replace($this,$result_l && $result_r);
}
}

到此为止此模式相关的类就介绍完毕,上述代码都是进过测试的,可直接复制粘贴运行来查看结果,现在我们就来看看客户端代码:

客户端代码一:

$context = new InterpreterContext();

$statement = new BooleanOrExpression (//可尝试将此操作符表达式换成BooleanAndExpression 运行一下 看看执行结果

//可尝试将LiteralExpression中实例化的参数改成其他值看看运算结果,或者直接将EqualsExpression对象换成BooleanOrExpression 或BooleanAndExpression 
new EqualsExpression(new LiteralExpression('four'),new LiteralExpression('four')), 

new EqualsExpression(new LiteralExpression('b'),new LiteralExpression('4'))
);

$statement->interpret($context);
if($context->lookup($statement)){
echo '条件成立';
} else {
echo '条件不成立';
}

客户端代码二

$context = new InterpreterContext();

$statement = new BooleanOrExpression(
new BooleanAndExpression(
new EqualsExpression(new LiteralExpression('4'),new LiteralExpression('4')),
new EqualsExpression(new LiteralExpression('4'),new LiteralExpression('4'))
),
new EqualsExpression(new LiteralExpression('b'),new LiteralExpression('4'))
);

$statement->interpret($context);
if($context->lookup($statement)){
echo '条件成立';
} else {
echo '条件不成立';
}

客户端代码三:

这是原文的客户端代码实例和上述客户端代码的区别在于使用了变量表达式VariableExpression

$context = new InterpreterContext();
$input = new VariableExpression('input');//这里定义了一个变量input 但并未赋值

$statement = new BooleanOrExpression(
new EqualsExpression($input,new LiteralExpression('four')),//这里变量表达式和文字表达式的值将进行一个是否相等的比较
new EqualsExpression($input,new LiteralExpression('4'))
);

foreach (array("four","4","52") as $val){
$input->setValue($val);//对input这个变量赋值
print "变量input的值为:$val:<br/>";
$statement->interpret($context);//进行比较并将比较结果存入InterpreterContext对象实例
if($context->lookup($statement)){//获取比较的结果
print "条件成立 <br/>";
} else {
print "条件不成立 <br/>";
}
}

上述代码经过测试都可以正常运行,有需要的朋友可以复制下来,运行一下看看结果。

以上这篇老生常谈PHP面向对象之解释器模式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP中将网页导出为Word文档的代码
May 25 PHP
PHPMailer使用教程(PHPMailer发送邮件实例分析)
Dec 06 PHP
深入解析PHP 5.3.x 的strtotime() 时区设定 警告信息修复
Aug 05 PHP
PHP curl 获取响应的状态码的方法
Jan 13 PHP
PHP base64编码后解码乱码的解决办法
Jun 19 PHP
destoon切换城市后实现logo旁边显示地区名称的方法
Aug 21 PHP
PHP提示Deprecated: mysql_connect(): The mysql extension is deprecated的解决方法
Aug 28 PHP
php数组转成json格式的方法
Mar 09 PHP
php图片添加水印例子
Jul 20 PHP
php常用数组array函数实例总结【赋值,拆分,合并,计算,添加,删除,查询,判断,排序】
Dec 07 PHP
PHP常用函数之获取汉字首字母功能示例
Oct 21 PHP
PHP终止脚本运行三种实现方法详解
Sep 01 PHP
phpmyadmin下载、安装、配置教程
May 16 #PHP
Windows下php+mysql5.7配置教程
May 16 #PHP
php使用curl实现ftp文件下载功能
May 16 #PHP
PHP jpgraph库的配置及生成统计图表:折线图、柱状图、饼状图
May 15 #PHP
php使用curl实现简单模拟提交表单功能
May 15 #PHP
PHP读取Excel类文件
May 15 #PHP
详谈php中 strtr 和 str_replace 的效率问题
May 14 #PHP
You might like
PHP 和 MySQL 基础教程(三)
2006/10/09 PHP
php根据某字段对多维数组进行排序的方法
2015/03/07 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
PHP 实现缩略图
2021/03/09 PHP
理解JavaScript中的对象 推荐
2011/01/09 Javascript
两个select多选模式的选项相互移动(示例代码)
2014/01/11 Javascript
JS父页面与子页面相互传值方法
2014/03/05 Javascript
JavaScript打印网页指定区域的例子
2014/05/03 Javascript
jquery 表单验证之通过 class验证表单不为空
2015/11/02 Javascript
jQuery+css实现的tab切换标签(兼容各浏览器)
2016/01/28 Javascript
webpack实用小功能介绍
2018/01/02 Javascript
vue.js select下拉框绑定和取值方法
2018/03/03 Javascript
create-react-app 修改为多入口编译的方法
2018/08/01 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
2018/09/21 Javascript
electron 如何将任意资源打包的方法步骤
2020/04/16 Javascript
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
[49:11]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第二场 12.20
2020/12/23 DOTA
[01:06:54]DOTA2-DPC中国联赛 正赛 RNG vs Dragon BO3 第一场 1月24日
2021/03/11 DOTA
python 文件与目录操作
2008/12/24 Python
使用Python实现简单的服务器功能
2017/08/25 Python
Python实现爬虫从网络上下载文档的实例代码
2018/06/13 Python
基于wxPython的GUI实现输入对话框(1)
2019/02/27 Python
Python基本类型的连接组合和互相转换方式(13种)
2019/12/16 Python
Python基于Socket实现简单聊天室
2020/02/17 Python
新加坡网上花店:FlowerAdvisor新加坡
2018/10/05 全球购物
SQL中where和having的区别
2012/06/17 面试题
宿舍卫生检讨书
2014/01/16 职场文书
《飞向蓝天的恐龙》教学反思
2014/04/09 职场文书
大学竞选班干部演讲稿
2014/08/21 职场文书
教师党员批评与自我批评发言稿
2014/10/15 职场文书
《珍珠鸟》教学反思
2016/02/16 职场文书
多人股份制合作协议书
2016/03/19 职场文书
只需要12页,掌握撰写一流商业计划书的技巧
2019/05/07 职场文书
CSS实现漂亮的时钟动画效果的实例代码
2021/03/30 HTML / CSS
MySQL锁机制
2021/04/05 MySQL
Python实现文本文件拆分写入到多个文本文件的方法
2021/04/18 Python