走穿java23种设计模式–23解释器模式详解
解释器模式是一种按照规定语法对表达式进行解析的方案,在项目中较少使用。
一.解释器模式的现实场景
蔡梁是一个军事迷,他特别喜欢看《特种兵作战》子类的电视剧和电影。他尤其喜欢里面的手语,通过手语同伴之间能过相互交流并作出准确的行动。他也经常和相邀一起去玩真人版CS,在真人版CS中他们也模仿电视剧或者电影里面的特种兵作战,他们手语的意思,然后用手语传达消息,他们玩得不亦乐乎。
在上面场景中,特种兵执行任务的时候,通常使用手语来传递消息,然后做出相应的行动,这类似于设计模式中的解释器模式。
二.解释器模式(Interpreter Pattern)的定义
给定一门语言,定义它的语法的一种表示,并定义一种解释器,该解释器使用该方法来解释语言中的语句
三.解释器模式的类图
四.解释器模式的五个角色
1.抽象表达式(Abstract Expression)角色
该角色声明一个所有的具体表达式角色都需要实现的抽象接口,该接口只要是含有一个解释器操作interpreter()方法
2.终结符表达式(Terminal Expression)角色
该角色实现了抽象表达式角色所需要的接口,文法中的每一个终结符都会有一个具体终结表达式与之相对应。
3.非终结符表达式(Norterminal Expression)角色
该角色是一个具体角色,文法中的每一条规则都对应一个非终结符表达式类。
4. 环境(Context)角色
该角色提供解释器之外的全局信息。
5.客户端(Client)角色
该角色创建一个抽象语法树,调用解释器操作方法。
五.解释器模式的优缺点
解释器模式中的优点
1.简单的语法解析工具
2.扩展性良好,若修改语法规则,只要修改相应的非终结符表达式即可,若扩展语法,只要增加非终结符类即可。
解释权模式的缺点
1.解释器模式会引起类膨胀。每一个语法都要产生一个非终结符表达式,语法比较复杂时可能会产生大量的类文件,不易维护。
2.采用递归方法。每个非终结符表达只关心与自己有关的表达式,每个表达式想要知道最终的结果,必须一层一层剥茧,无论是面向过程的语言还是面向对象的语言,递归都是要在必要条件下才能使用的,它使程序不易调试。
六.解释器模式的使用场景
1.重复发生的问题可以使用解释器模式。
比如:多个应用服务器。每天产生大量的日志,系统需要对日志进行分析处理。由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,非总结表达式就需要制定。
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