走穿java23种设计模式,最后一个设计模式--23解释器模式详解

版权声明:本文为博主原创文章。只要评论中留言就可以转载。 https://blog.csdn.net/wenzhi20102321/article/details/80601168

走穿java23种设计模式–23解释器模式详解

解释器模式是一种按照规定语法对表达式进行解析的方案,在项目中较少使用。

一.解释器模式的现实场景

蔡梁是一个军事迷,他特别喜欢看《特种兵作战》子类的电视剧和电影。他尤其喜欢里面的手语,通过手语同伴之间能过相互交流并作出准确的行动。他也经常和相邀一起去玩真人版CS,在真人版CS中他们也模仿电视剧或者电影里面的特种兵作战,他们手语的意思,然后用手语传达消息,他们玩得不亦乐乎。
在上面场景中,特种兵执行任务的时候,通常使用手语来传递消息,然后做出相应的行动,这类似于设计模式中的解释器模式。

二.解释器模式(Interpreter Pattern)的定义

给定一门语言,定义它的语法的一种表示,并定义一种解释器,该解释器使用该方法来解释语言中的语句

三.解释器模式的类图

1

四.解释器模式的五个角色

1.抽象表达式(Abstract Expression)角色

该角色声明一个所有的具体表达式角色都需要实现的抽象接口,该接口只要是含有一个解释器操作interpreter()方法

2.终结符表达式(Terminal Expression)角色

该角色实现了抽象表达式角色所需要的接口,文法中的每一个终结符都会有一个具体终结表达式与之相对应。

3.非终结符表达式(Norterminal Expression)角色

该角色是一个具体角色,文法中的每一条规则都对应一个非终结符表达式类。

4. 环境(Context)角色

该角色提供解释器之外的全局信息。

5.客户端(Client)角色

该角色创建一个抽象语法树,调用解释器操作方法。

五.解释器模式的优缺点

解释器模式中的优点

1.简单的语法解析工具

2.扩展性良好,若修改语法规则,只要修改相应的非终结符表达式即可,若扩展语法,只要增加非终结符类即可。

解释权模式的缺点

1.解释器模式会引起类膨胀。每一个语法都要产生一个非终结符表达式,语法比较复杂时可能会产生大量的类文件,不易维护。

2.采用递归方法。每个非终结符表达只关心与自己有关的表达式,每个表达式想要知道最终的结果,必须一层一层剥茧,无论是面向过程的语言还是面向对象的语言,递归都是要在必要条件下才能使用的,它使程序不易调试。

六.解释器模式的使用场景

1.重复发生的问题可以使用解释器模式。

比如:多个应用服务器。每天产生大量的日志,系统需要对日志进行分析处理。由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,非总结表达式就需要制定。

2.一个简单语法需要解释的场景。

七.解释器模式的示例

这里使用现实场景中的加减乘除运算做代码示例。

示例的类图

2

示例的代码

1.抽象表达式角色:算式表达式ArithmeticExpression

package p23_interpreter;

/**
 * 抽象表达式角色:算式表达式
 */
public interface ArithmeticExpression {
    //根据保存的值做出相应的运行并返回结果(子类做实际运算)
    int interpret(Variables variables);
}

2.终结符表达式:算术表达式中的变量Variable

package p23_interpreter;

/**
 * 终结符表达式:算术表达式中的变量
 */
public class Variable implements ArithmeticExpression{

    //根据原本定义的符号(对象),获取到对应的数值
    //比如X知道自己是10.。。
    @Override
    public int interpret(Variables variables) {
        return variables.get(this);
    }
}

3. 环境角色:Variables

package p23_interpreter;

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

/**
 * 环境角色:使用Map保存各个变量的值:符号(对象)+数值
 * 比如,固定X的值10,Y的值为100等等
 */
public class Variables {

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

    public void put(Variable variable, int value) {
        map.put(variable, value);
    }

    public int get(Variable variable) {
        return map.get(variable);
    }

}

4.非终结符表达式角色:加法运算 Plus

package p23_interpreter;


/**
 * 非终结符表达式角色:加法运算
 */
public class Plus implements ArithmeticExpression {
    ArithmeticExpression left;
    ArithmeticExpression right;

    //传入要运算的符号(对象),比如这里传入x,y,不过这里的x,y在其他地方已经被定义好数值的
    public Plus(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;

    }


    //Variables是一个Map里面具体的数据
    //这里通过interpret方法得到Map里面的具体数值,比如上面说的传入x,y那么interpret后就得到他们对应的数值
    //最后相加得到想要的结果
    @Override
    public int interpret(Variables variables) {
        return left.interpret(variables)+right.interpret(variables);
    }
}

5.非终结符表达式角色:减法运算 Subtract

package p23_interpreter;


/**
 * 非终结符表达式角色:减法运算
 */
public class Subtract implements ArithmeticExpression {
    ArithmeticExpression left;
    ArithmeticExpression right;

    //传入要运算的符号(对象),比如这里传入x,y,不过这里的x,y在其他地方已经被定义好数值的
    public Subtract(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;

    }


    //Variables是一个Map里面具体的数据
    //这里通过interpret方法得到Map里面的具体数值,比如上面说的传入x,y那么interpret后就得到他们对应的数值
    //最后相减得到想要的结果
    @Override
    public int interpret(Variables variables) {
        return left.interpret(variables) - right.interpret(variables);
    }
}

6.非终结符表达式角色:乘法运算 Multiply

package p23_interpreter;


/**
 * 非终结符表达式角色:乘法运算
 */
public class Multiply implements ArithmeticExpression {
    ArithmeticExpression left;
    ArithmeticExpression right;

    //传入要运算的符号(对象),比如这里传入x,y,不过这里的x,y在其他地方已经被定义好数值的
    public Multiply(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;

    }


    //Variables是一个Map里面具体的数据
    //这里通过interpret方法得到Map里面的具体数值,比如上面说的传入x,y那么interpret后就得到他们对应的数值
    //最后相乘得到想要的结果
    @Override
    public int interpret(Variables variables) {
        return left.interpret(variables) * right.interpret(variables);
    }
}

7.非终结符表达式角色:除法运算 Division

package p23_interpreter;


/**
 * 非终结符表达式角色:除法运算
 */
public class Division implements ArithmeticExpression {
    ArithmeticExpression left;
    ArithmeticExpression right;

    //传入要运算的符号(对象),比如这里传入x,y,不过这里的x,y在其他地方已经被定义好数值的
    public Division(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;

    }


    //Variables是一个Map里面具体的数据
    //这里通过interpret方法得到Map里面的具体数值,比如上面说的传入x,y那么interpret后就得到他们对应的数值
    //最后相除得到想要的结果
    @Override
    public int interpret(Variables variables) {
        return left.interpret(variables)/ right.interpret(variables);
    }
}

8.客户端:测试类InterpreterDemo

package p23_interpreter;

/**
 * 客户端:测试类
 */
public class InterpreterDemo {

    public static void main(String[] args) {
        //定义可以存放变量对象和变量值数据的对象
        Variables variables = new Variables();

        //定义变量符号(对象),分别定义x,y,z
        Variable x = new Variable();
        Variable y = new Variable();
        Variable z = new Variable();

        //分别給x,y,z定义具体的数值
        variables.put(x, 10);
        variables.put(y, 20);
        variables.put(z, 30);

        //计算x*(y+z/x)-x
        //这里拆分写
        //1. 计算除法z/x
        Division division = new Division(z, x);
        //2.计算加法y+z/x
        Plus plus = new Plus(y, division);
        //3.计算乘法x*(y+z/x)
        Multiply multiply = new Multiply(x, plus);
        //4.最后计算减法:x*(y+z/x)-x
        Subtract subtract = new Subtract(multiply, x);

        //获取最终的结果(把x,y,z的具体值的对象传进去)
        int result = subtract.interpret(variables);

        //得到结果:220
        System.out.println("result=" + result);


    }

}

程序运行结果;

result=220

其实解释器模式就像我们数学中很多算式中那样,如果好多地方用到几个具体的值,比如用x,y表示,
后面很多地方如果用到用到这两个值,只需要用x,y表示,就可以了,这样看起来简洁明了!

状态模式模式就为大家介绍到这里。

大家如果对其他设计模式有兴趣可以看看我之前的博客:

22状态模式:https://blog.csdn.net/wenzhi20102321/article/details/80558128

21访问者模式:https://blog.csdn.net/wenzhi20102321/article/details/80546326

20备忘录模式:https://blog.csdn.net/wenzhi20102321/article/details/80468151

19观察者模式:https://blog.csdn.net/wenzhi20102321/article/details/80330335

18中介者模式:https://blog.csdn.net/wenzhi20102321/article/details/79394668

17迭代器模式:http://blog.csdn.net/wenzhi20102321/article/details/79343423

16策略模式:http://blog.csdn.net/wenzhi20102321/article/details/79336521

15责任链模式:http://blog.csdn.net/wenzhi20102321/article/details/79333899

14命令模式:http://blog.csdn.net/wenzhi20102321/article/details/79323404

13模板方法模式:http://blog.csdn.net/wenzhi20102321/article/details/79284870

12享元模式:http://blog.csdn.net/wenzhi20102321/article/details/78724677

11外观模式:http://blog.csdn.net/wenzhi20102321/article/details/78639087

10桥梁模式:http://blog.csdn.net/wenzhi20102321/article/details/78566532

9组合模式:http://blog.csdn.net/wenzhi20102321/article/details/78463190

8适配器模式:http://blog.csdn.net/wenzhi20102321/article/details/78389326

7装饰模式:http://blog.csdn.net/wenzhi20102321/article/details/78336273

6代理模式:http://blog.csdn.net/wenzhi20102321/article/details/78209493

创建型模式详解:http://blog.csdn.net/wenzhi20102321/article/details/78175558

5原型模式:http://blog.csdn.net/wenzhi20102321/article/details/78167984

4建造者模式:http://blog.csdn.net/wenzhi20102321/article/details/78163855

3抽象工厂模式:http://blog.csdn.net/wenzhi20102321/article/details/78153437
2工厂方法模式:http://blog.csdn.net/wenzhi20102321/article/details/78129065
可以仔细对比一下工厂方法模式和抽象工厂模式,看看概念,看看类图,看看代码,就会明白了。

1单例模式:http://blog.csdn.net/wenzhi20102321/article/details/77882203

java 23种设计模式介绍:http://blog.csdn.net/wenzhi20102321/article/details/54601909

共勉;你若盛开,蝴蝶自来。

猜你喜欢

转载自blog.csdn.net/wenzhi20102321/article/details/80601168