老生常谈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 相关文章推荐
NOT NULL 和NULL
Jan 15 PHP
php 变量未定义等错误的解决方法
Jan 12 PHP
PHP学习之整理字符串
Apr 17 PHP
请离开include_once和require_once
Jul 18 PHP
php判断字符串在另一个字符串位置的方法
Feb 27 PHP
Yii2 rbac权限控制之菜单menu实例教程
Apr 28 PHP
PHP的AES加密算法完整实例
Jul 20 PHP
phpmyadmin下载、安装、配置教程
May 16 PHP
浅谈ThinkPHP5.0版本和ThinkPHP3.2版本的区别
Jun 17 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
php实现的PDO异常处理操作分析
Dec 27 PHP
php curl获取https页面内容,不直接输出返回结果的设置方法
Jan 15 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
php5.2时间相差8小时
2007/01/15 PHP
php根据操作系统转换文件名大小写的方法
2014/02/24 PHP
php计算给定时间之前的函数用法实例
2015/04/03 PHP
php使用yield对性能提升的测试实例分析
2019/09/19 PHP
通过实例解析PHP数据类型转换方法
2020/07/11 PHP
document.all还是document.getElementsByName?
2006/07/21 Javascript
利用cookie记住背景颜色示例代码
2013/11/04 Javascript
js中一个函数获取另一个函数返回值问题探讨
2013/11/21 Javascript
js验证整数加保留小数点的简单实例
2013/12/02 Javascript
js 判断图片是否加载完以及实现图片的预下载
2014/08/14 Javascript
使用jquery操作session方法分享
2015/01/22 Javascript
jQuery数据缓存用法分析
2015/02/20 Javascript
js实现仿京东2级菜单效果(带延时功能)
2015/08/27 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
详解VUE的状态控制与延时加载刷新
2017/03/27 Javascript
AngularJS改变元素显示状态
2017/04/20 Javascript
React Native仿美团下拉菜单的实例代码
2017/08/08 Javascript
微信小程序实现两边小中间大的轮播效果的示例代码
2018/12/07 Javascript
js 将线性数据转为树形的示例代码
2019/05/28 Javascript
[01:12:08]LGD vs OG 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.24
2019/09/10 DOTA
python 简单的绘图工具turtle使用详解
2017/06/21 Python
itchat和matplotlib的结合使用爬取微信信息的实例
2017/08/25 Python
基于python检查SSL证书到期情况代码实例
2020/04/04 Python
Python常驻任务实现接收外界参数代码解析
2020/07/21 Python
python输入中文的实例方法
2020/09/14 Python
如果一个类实现了多个接口但是这些接口有相同的方法名将会怎样
2013/06/16 面试题
金融行业务员的自我评价
2013/12/13 职场文书
文明宿舍获奖感言
2014/02/07 职场文书
高中学生评语大全
2014/04/25 职场文书
环保倡议书100字
2014/05/15 职场文书
纪律教育学习月活动总结
2014/08/27 职场文书
党的群众路线教育实践活动个人对照检查材料(四风)
2014/11/05 职场文书
银行员工考核评语
2014/12/31 职场文书
党员违纪检讨书
2015/05/05 职场文书
Python利用Turtle绘制哆啦A梦和小猪佩奇
2022/04/04 Python
Oracle 多表查询基本语法实例
2022/04/18 Oracle