[工作中的设计模式]解释器模式模式Interpreter

一、模式解析

  解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

以上是解释器模式的类图,事实上我很少附上类图,但解释器模式确实比较抽象,为了便于理解还是放了上来,此模式的要点是:

1、客户端提供一个文本、表达式或者其他,约定解析格式

2、针对文本中可以分为终结符表达式非终结符表达式

3、终结符表达式无需进一步解析,但仍需要转化为抽象接口的实例

4、针对非终结表达式,没一种标示需要定义一种解析类,如果后续有扩展,则进一步扩展一种解析类,并修改解析分支即可完成扩展

二、模式代码

1、定义整体环境类,保存除了解析器外,其他全局信息

package interpreter.patten;

public class Context {
    private String input;
    private String output;
    public String getInput() {
        return input;
    }
    public void setInput(String input) {
        this.input = input;
    }
    public String getOutput() {
        return output;
    }
    public void setOutput(String output) {
        this.output = output;
    }
}

2、定义抽象解析器

package interpreter.patten;

public abstract class AbstractExpression {
    public abstract void interpret(Context context);
}

3、定义终结符解析器

package interpreter.patten;

public class TerminalExpression extends AbstractExpression {

    @Override
    public void interpret(Context context) {
        System.out.println("终结符解析器");
    }
}

4、定义非终结符表达式

package interpreter.patten;

public class UnTerminalExpression extends AbstractExpression {

    @Override
    public void interpret(Context context) {
        System.out.println("非终结符解析器");
    }
}

5、定义客户端类

package interpreter.patten;

import java.util.ArrayList;
import java.util.List;

public class Client {
    public static void main(String[] args) {
        Context context=new Context();
        List<AbstractExpression> list=new ArrayList<AbstractExpression>();
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        for(AbstractExpression expression:list){
            expression.interpret(context);
        }
    }
}

6、客户端执行结果

终结符解析器
非终结符解析器
终结符解析器
非终结符解析器
终结符解析器
非终结符解析器

三、应用场景

以上模式代码完整的实现了类图中的所有内容,并打印出了结果,但是又显得毫无意义,看起来比较蠢,这是因为在我们的实际使用中解释器模式使用非常稀少,他只有在做特定公式的解析或者语言解析才会用到,很不幸,目前我的工作中似乎没有可以完整的展示此模式的例子,但是为了加深印象,我们采用《java与模式》中的例子进行说明

此为java与模式中提供的相关例子,主要用于解析条件判断语句,例如:A and B,A or B ,not A等条件语句,表达式分为几类

1、终结符表达式-常量表达式,主要显示true或者false

2、终结符表达式=-变量表达式,主要是需要判断的条件

3、非终结符表达式-各种运算符,包括:与或非

四、场景代码

1、环境(Context)类定义出从变量到布尔值的一个映射

package interpreter.example;

import java.util.HashMap;
import java.util.Map;

public class Context {

    private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>();

    public void assign(Variable var , boolean value){
        map.put(var, new Boolean(value));
    }

    public boolean lookup(Variable var) throws IllegalArgumentException{
        Boolean value = map.get(var);
        if(value == null){
            throw new IllegalArgumentException();
        }
        return value.booleanValue();
    }
}

2、定义抽象表达式

package interpreter.example;
public abstract class Expression {
    /**
     * 以环境为准,本方法解释给定的任何一个表达式
     */
    public abstract boolean interpret(Context ctx);
    /**
     * 检验两个表达式在结构上是否相同
     */
    public abstract boolean equals(Object obj);
    /**
     * 返回表达式的hash code
     */
    public abstract int hashCode();
    /**
     * 将表达式转换成字符串
     */
    public abstract String toString();
}

3、定义常量表达式

package interpreter.example;
public class Constant extends Expression{

    private boolean value;

    public Constant(boolean value){
        this.value = value;
    }

    @Override
    public boolean equals(Object obj) {

        if(obj != null && obj instanceof Constant){
            return this.value == ((Constant)obj).value;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {

        return value;
    }

    @Override
    public String toString() {
        return new Boolean(value).toString();
    }

}

4、定义变量表达式

package interpreter.example;
public class Variable extends Expression {

    private String name;

    public Variable(String name){
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {

        if(obj != null && obj instanceof Variable)
        {
            return this.name.equals(
                    ((Variable)obj).name);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public boolean interpret(Context ctx) {
        return ctx.lookup(this);
    }

}

5、定义逻辑与

package interpreter.example;
public class And extends Expression {

    private Expression left,right;

    public And(Expression left , Expression right){
        this.left = left;
        this.right = right;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof And)
        {
            return left.equals(((And)obj).left) &&
                right.equals(((And)obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {

        return left.interpret(ctx) && right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " AND " + right.toString() + ")";
    }

}

6、定义逻辑或

package interpreter.example;
public class Or extends Expression {
    private Expression left,right;

    public Or(Expression left , Expression right){
        this.left = left;
        this.right = right;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Or)
        {
            return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return left.interpret(ctx) || right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " OR " + right.toString() + ")";
    }

}

7、定义逻辑非

package interpreter.example;
public class Not extends Expression {

    private Expression exp;

    public Not(Expression exp){
        this.exp = exp;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Not)
        {
            return exp.equals(
                    ((Not)obj).exp);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return !exp.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(Not " + exp.toString() + ")";
    }

}

8、定义客户端代码

package interpreter.example;
public class Client {

    public static void main(String[] args) {
        Context ctx = new Context();
        Variable x = new Variable("x");
        Variable y = new Variable("y");
        Constant c = new Constant(true);
        ctx.assign(x, false);
        ctx.assign(y, true);

        Expression exp = new Or(new And(c,x) , new And(y,new Not(x)));
        System.out.println("x=" + x.interpret(ctx));
        System.out.println("y=" + y.interpret(ctx));
        System.out.println(exp.toString() + "=" + exp.interpret(ctx));
    }

}

五、总结

解释器模式可以很容易改变和扩展解释方法,但是由于每个文本都需要定义一个类,会导致后期很难管理,因此不太常用。

注:此文代码和案例都是一些经典实现,并无工作体验,以后如果有具体案例再替换

时间: 2024-10-13 20:39:43

[工作中的设计模式]解释器模式模式Interpreter的相关文章

[工作中的设计模式]享元模式模式FlyWeight

一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建 模式要点: 1.享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分 2.共性部分的抽象就是此模

[工作中的设计模式]策略模式stategy

一.模式解析 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 策略模式的关键点为: 1.多种算法存在 2.算法继承同样的接口,执行同样的行为,为可以替代的 3.算法调用者唯一,算法调用者可以灵活改变自己需要调用的算法,从而实现计算. 二.模式代码 算法接口: /** * 算法统一接口,所有算法继承此接口 * @author zjl * @time 2016-1-24 * */ public interface IStra

[工作中的设计模式]模板模式

一.模式解析 准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现.这就是模板方法模式的用意 模板模式的关键点为: 1.有一个父类,将整体业务逻辑和公用方法进行封装: 2.父类将具体的有差异的业务定义为抽象方法: 3.子类继承父类后,实现这些抽象方法,完成对自己业务流程的: 4.子类不可以改变父类的整体业务逻辑流程: 5.子类也可以覆盖父类中其他方法,实现定制化业务

[工作中的设计模式]原型模式prototype

一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.prototype.run=function(){ alert(this.name+" is running"; } 此处的原型是js的特殊定义,在原型上定义的属性和方法所有的类进行共享. 不过设计模式中的原型模式指的是:将已有的对象作为原型,拷贝出一份具有相同属性的新的对象. 模式定义为:原型

[工作中的设计模式]备忘录模式memento

一.模式解析 备忘录对象是一个用来存储另外一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态.备忘录模式常常与命令模式和迭代子模式一同使用. 备忘录模式可以根据客户指令,将相应的对象特有属性进行快照,如果客户要恢复对象,则根据快照提供的特有属性进行还原. 二.模式代码 package memento.patten; /** *备忘录类,同时指定要保存的对象属性

[工作中的设计模式]组合模式compnent

一.模式解析 将对象组合成树形结构以表示“部分整体”的层次结构.组合模式使得用户对单个对象和使用具有一致性. 组合模式的要点是: 1.对象整体以树形层次结构进行展示 2.树的根节点和子节点均可以添加删除子节点,叶子节点无子节点 3.可以通过节点的行为动作调用并展示他所有自己点的行为 4.为了方便的实现无限节点的扩展,我们通常定义一个公共的接口,所有子节点和叶子节点均实现此接口 二.模式代码 1.公共接口,供所有子节点和叶子节点实现 package component.patten; public

[工作中的设计模式]桥接模式bridge

一.模式解析: 策略模式一节讲过,通过扩展持有者,使持有者形成抽象类,然后实现多个具体持有者,策略模式可以转化为桥接模式. 桥接模式定义为:将抽象部分与实现部分分离,使它们都可以独立的变化,在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,使用桥接模式可以应对多维度的变化. 主要有两个要点 1.有两个维度的变化,彼此的变化应该不会受到对方的干扰 2.通过接口进行关联,共有n*m种组合 3.其中一个维度,保存这另外一个维度的引用 二.模式代码: 维度一 interface Impl

Android中的设计模式-工厂方法模式

简单工厂&工厂方法 一直以来总是分不清简单工厂,工厂方法,抽象工厂这三个设计模式的区别,倒不是不理解其区别,而是总是记忆混淆,傻傻分不清楚,所以再重新总结一下区别,并记录下来,下次再混淆时,可以拿出来看看.这节先说简单工厂和工厂方法,下一节再说抽象工厂. 工厂方法中其实就包含了简单工厂,简单工厂也称为静态工厂方法, 简单工厂模式(Simple Factory) 类图 简单工厂模式又称为静态工厂方法模式,是工厂方法模式的一种,简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产

php中的设计模式之--门面模式

<?php /** (1)外观模式(Facade)也叫门面模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 为一些复杂的子系统提供一组接口 (2)主要角色 门面(Facade)角色 ? 此角色将被客户端调用 ? 知道哪些子系统负责处理请求 ? 将用户的请求指派给适当的子系统 子系统(subsystem)角色 ? 实现子系统的功能 ? 处理由Facade对象指派的任务 ? 没有Facade的相关信息,可以被客户端直接调用 ? 可以同时有一