设计模式解密(21)- 解释器模式

1、简介

定义:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

主要解决:对于一些固定文法构建一个解释句子的解释器。

本质:分离实现,解释执行。Interpreter模式其实就是一种简单的语法解释器构架。

英文:Interpreter

类型:行为型

2、类图及组成

(引)类图:


组成:
  AbstractExpression(抽象表达式):定义解释器的接口,约定解释器的解释操作。

  TerminalExpression(终结符表达式):用来实现语法规则中和终结符相关的操作,不再包含其它的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的叶子对象,可以有多种终结符解释器。

  NonterminalExpression(非终结符表达式):用来实现语法规则中非终结符相关的操作,通常一个解释器对应一个语法规则,可以包含其它的解释器,如果用组合模式来构建抽象语法树的话,就相当于组合模式中的组合对象,可以有多种非终结符解释器。

  Context(上下文):它包含了解释器之外一些其他的全局信息;通常包含各个解释器需要的数据,或是公共的功能。

  Client(客户端):指的是使用解释器的客户端,通常在这里去把按照语言的语法做的表达式,转换成为使用解释器对象描述的抽象语法树,然后调用解释操作。

代码结构:

/**
 * 抽象表达式
 */
public abstract class AbstractExpression {
    /**
     * 解释的操作
     * @param ctx 上下文对象
     */
    public abstract void interpret(Context ctx);
}

/**
 * 终结符表达式
 */
public class TerminalExpression extends AbstractExpression{
    public void interpret(Context ctx) {
        //实现与语法规则中的终结符相关联的解释操作
    }
}

/**
 * 非终结符表达式
 */
public class NonterminalExpression extends AbstractExpression{
    public void interpret(Context ctx) {
        //实现与语法规则中的非终结符相关联的解释操作
    }
}

/**
 * 上下文,包含解释器之外的一些全局信息
 */
public class Context {

}

/**
 * 使用解释器的客户
 */
public class Client {
    //主要按照语法规则对特定的句子构建抽象语法树
    //然后调用解释操作
}

3、实例引入

场景: 与(and)、或(or)、非(not) 的一套解析器

抽象表达式:

package com.designpattern.Interpreter;

/**
 *  抽象表达式 -- BooleanExp
 *  定义:
 *      BooleanExp -->> VariableExp | Constant | OrExp | AndExp | NotExp | ‘(‘ BooleanExp ‘)‘
 *      AndExp -->> BooleanExp ‘and‘ BooleanExp
 *      OrExp -->> BooleanExp ‘or‘ BooleanExp
 *      NotExp -->> BooleanExp ‘not‘ BooleanExp
 *      Constant -->> ‘true‘ | ‘false‘
 *      VariableExp -->> ‘A‘ | ‘B‘ | ... | ‘Z‘
 *
 * @author Json<<[email protected]>>
 */
public interface BooleanExp {

    public abstract boolean Evaluate(Context c);

    public abstract BooleanExp Replace(String var, BooleanExp exp);

    public abstract BooleanExp Copy();
}

3个具体表达式:

package com.designpattern.Interpreter;

/**
 * 非终结符表达式 -- and
 * @author Json<<[email protected]>>
 */
public class AndExp implements BooleanExp {
    private BooleanExp operand1;
    private BooleanExp operand2;

    public AndExp(BooleanExp oper1, BooleanExp oper2) {
        operand1 = oper1;
        operand2 = oper2;
    }

    public boolean Evaluate(Context c) {
        return operand1.Evaluate(c) && operand2.Evaluate(c);
    }

    public BooleanExp Copy() {
        return new AndExp(operand1.Copy(), operand2.Copy());
    }

    public BooleanExp Replace(String var, BooleanExp exp) {
        return new AndExp(operand1.Replace(var, exp),operand2.Replace(var, exp));
    }
}
package com.designpattern.Interpreter;

/**
 * 非终结符表达式 -- or
 * @author Json<<[email protected]>>
 */
public class OrExp implements BooleanExp {
    private BooleanExp operor1;
    private BooleanExp operor2;

    public OrExp(BooleanExp oper1, BooleanExp oper2) {
        operor1 = oper1;
        operor2 = oper2;
    }

    public boolean Evaluate(Context c) {
        return operor1.Evaluate(c) || operor2.Evaluate(c);
    }

    public BooleanExp Copy() {
        return new OrExp(operor1.Copy(), operor2.Copy());
    }

    public BooleanExp Replace(String var, BooleanExp exp) {
        return new OrExp(operor1.Replace(var, exp),operor2.Replace(var, exp));
    }
}
package com.designpattern.Interpreter;

/**
 * 非终结符表达式 -- not
 * @author Json<<[email protected]>>
 */
public class NotExp implements BooleanExp {
    private BooleanExp opernot1;

    public NotExp(BooleanExp oper1) {
        opernot1 = oper1;
    }

    public boolean Evaluate(Context c) {
        return !(opernot1.Evaluate(c));
    }

    public BooleanExp Copy() {
        return new NotExp(opernot1.Copy());
    }

    public BooleanExp Replace(String var, BooleanExp exp) {
        return new NotExp(opernot1.Replace(var, exp));
    }
}

终结符表达式:

package com.designpattern.Interpreter;

/**
 * 终结符表达式
 * @author Json<<[email protected]>>
 */
public class VariableExp implements BooleanExp {
    private String name;

    public VariableExp(String _name) {
        name = _name;
    }

    public boolean Evaluate(Context c) {
        return c.LookUp(name);
    }

    public BooleanExp Copy() {
        return new VariableExp(name);
    }

    public BooleanExp Replace(String var, BooleanExp exp) {
        if(var.equals(name)) {
            return exp.Copy();
        } else {
            return new VariableExp(name);
        }
    }
}

上下文:

package com.designpattern.Interpreter;

import java.util.Hashtable;

/**
 * 上下文
 * @author Json<<[email protected]>>
 */
public class Context  {
    private Hashtable<String, Boolean> context = new Hashtable<String, Boolean>();

    public void Assign(String name, boolean val) {
        context.put(name, new Boolean(val));
    }

    public boolean LookUp(String name) {
        return ((Boolean)context.get(name)).booleanValue();
    }

    public Context() {
    }
}

客户端测试:

package com.designpattern.Interpreter;

/**
 * 客户端测试
 * @author Json<<[email protected]>>
 */
public class Client  {
    public static void main(String[] args) {
        Context context = new Context();

        VariableExp x = new VariableExp("X");
        VariableExp y = new VariableExp("Y");
        VariableExp z = new VariableExp("Z");

        context.Assign("X", true);
        context.Assign("Y", false);
        context.Assign("Z", true);

        //测试表达式 :(z and x) and (y and (not x))
        BooleanExp expression = new AndExp(new AndExp(z, x),new AndExp(y, new NotExp(x)));
        boolean result = expression.Evaluate(context);
        System.out.println("(z and x) and (y and (not x))表达式结果:" + result);

        //测试表达式 :(z and x) or (y and (not x))
        BooleanExp expression1 = new OrExp(new AndExp(z, x),new AndExp(y, new NotExp(x)));
        boolean result1 = expression1.Evaluate(context);
        System.out.println("(z and x) or (y and (not x))表达式结果:" + result1);
    }
}

结果:

(z and x) and (y and (not x))表达式结果:false
(z and x) or (y and (not x))表达式结果:true

4、优缺点

优点:

  易于实现语法:在解释器模式中,一条语法规则用一个解释器对象来解释执行,对于解释器的实现来讲,功能就变得比较简单,只需要考虑这一条语法规则的实现就好了,其它的都不用管。

  易于扩展新的语法:正是由于采用一个解释器对象负责一条语法规则的方式,使得扩展新的语法非常容易,扩展了新的语法,只需要创建相应的解释器对象,在创建抽象语法树的时候使用这个新的解释器对象就可以了。

缺点:

  引起类爆炸:每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。

  采用递归调用方法:每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。

  效率问题:解释器模式由于使用了大量的循环和递归,效率是个不容忽视的问题,特别是用于解析复杂、冗长的语法时,效率是非常低的。

5、场景

当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式。

注意:
  1、语法相对应该比较简单,太复杂的语法不合适使用解释器模式;

  2、效率要求不是很高,对效率要求很高的情况下,不适合使用解释器模式。

6、总结

解释器模式在实际的系统开发中使用的非常少,因为它会引起效率、性能以及维护等问题,一般在大中型的框架型项目能够找到它的身影,比如一些数据分析工具、报表设计工具、科学计算工具等等。

PS:数学运算常用运算解析工具:Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包,功能都异常强大,而且非常容易使用,效率也还不错!!!

PS:源码地址   https://github.com/JsonShare/DesignPattern/tree/master

PS:原文地址  http://www.cnblogs.com/JsonShare/p/7367535.html

时间: 2024-10-28 22:10:07

设计模式解密(21)- 解释器模式的相关文章

大话设计模式Python实现-解释器模式

解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 __author__ = 'Andy' 5 """ 6 大话设计模式 7 设计模式--解释器模式 8 解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种

【设计模式】15.解释器模式

1 package com.shejimoshi.behavioral.Interpreter; 2 3 4 /** 5 * 功能:演奏文本 6 * 时间:2016年3月3日上午9:26:19 7 * 作者:cutter_point 8 */ 9 public class PlayContext 10 { 11 private String text; 12 13 public PlayContext() 14 { 15 } 16 17 public PlayContext(String tex

Java进阶篇设计模式之九----- 解释器模式和迭代器模式

前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern). 解释器模式 简介 解释器模式顾名思义,就是对某事物进行解释.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 解释器模式

设计模式--19、解释器模式

定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式. 解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器Nontermi

[设计模式-行为型]解释器模式(Interpreter)

一句话 看起来是用来解释一种语言的文法.(类似不同的解释器子类解释不同的字符) 和编译器类似的解释器, 实际状况可能使用的比较少. 概括 解析 INTERPRETER-俺有一个<泡MM真经>,上面有各种泡MM的攻略,比如说去吃西餐的步骤.去看电影的方法等等,跟MM约会时,只要做一个Interpreter,照着上面的脚本执行就可以了. 解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子.解释器模式将描述怎样在有了

设计模式学习笔记——解释器模式

1.特点:若某特定问题发生的频率足够高时考虑,需定义文法表示与解释器本身. 2.概念:在软件开发特别是DSL开发中常常需要使用一些相对较复杂的业务语言,如果业务语言使用频率足够高,且使用普通的编程模式来实现会导致非常复杂的变化,那么就可以考虑使用解释器模式构建一个解释器对复杂的业务语言进行翻译.这种做法虽然效率相对较低,但可以允许用户使用自定义的业务语言来处理逻辑,因此在效率不是关键问题的场合还是较为有用的. 3.类图: 4.程序实现: public static class ChineseEn

《Java设计模式》之解释器模式

解释器模式是类的行为模式.给定一个语言之后,解释器模式能够定义出其文法的一种表示,并同一时候提供一个解释器. client能够使用这个解释器来解释这个语言中的句子. 解释器模式的结构 以下就以一个示意性的系统为例,讨论解释器模式的结构.系统的结构图例如以下所看到的: 模式所涉及的角色例如以下所看到的: (1)抽象表达式(Expression)角色:声明一个全部的详细表达式角色都须要实现的抽象接口.这个接口主要是一个interpret()方法,称做解释操作. (2)终结符表达式(Terminal

设计模式(15)--Interpreter(解释器模式)--行为型

1.模式定义: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 2.模式特点: 解释器模式在实际的系统开发中使用的非常少,因为它会引起效率.性能以及维护等问题,一般在大中型的框架型项目能够找到它的身影,比如一些数据分析工具.报表设计工具.科学计算工具等等,若你确实遇到“一种特定类型的问题发生的频率足够高”的情况,准备使用解释器模式时,可以考虑一下Expression4J.MESP(Math

Java描述设计模式(14):解释器模式

本文源码:GitHub·点这里 || GitEE·点这里 一.解释器模式 1.基础概念 解释器模式是对象的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的表达式. 2.模式图解 3.核心角色 (1).抽象表达式 Express:声明具体表达式角色需要实现的抽象接口,该接口主要提供一个interpret()方法,称做解释操作. (2).终结符表达式 TerminalExpress:实现抽象表达式角色接口,主要是一个i

设计模式漫谈之解释器模式

今天5月1号了,回郑州,在家待了三天.打了几天手游,花了不少钱.家里准备再盖座房子,我也应该为家里做些贡献.真他娘累,30多了,单身,现在已有些恐婚了.近期有空要做个记账软件,否则钱花的太快了.这个月,20多号还要软考,我这应该是考不过了,基本放弃了.老板原说涨3K,又变成2K,坑,套路. 近期我写的代码有上层到github和csdn code中,这种托管代码平台绝对是程序员的福利. 闲话少扯,继续说设计模式,从今天起就开始说行为模式.刚看到C#版本都更新到8.0了,让我意识到,编程思想很重要,