说明:本文介绍行为型设计模式之一的解释器模式
定义
解释器模式(Interpreter Pattern)指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。解释器模式是一种按照规定的文法(语法)进行解析的模式,属于行为型设计模式。
(引自《设计模式就该这样学》P385)
自定义脚本
这里介绍《秒懂设计模式》这本书中的举例,假设我们需要定义一个刷怪脚本,脚本语言如下,执行顺序为自上而下。
shell
BEGIN // 脚本开始
MOVE 500,600 // 鼠标移动到屏幕(500, 600)的位置
BEGIN LOOP 5 // 开始循环5次
LEFT_CLICK; // 循环鼠标单击左键
DELAY 1; // 每次延迟1秒
END; // 循环结束
RIGHt_LEFT; // 按下鼠标左键
DELAY 7200; // 延迟7200秒
END: // 脚本结束
分析一下,这个脚本中包含了一下操作:
-
移动鼠标
-
鼠标左键单击(包含按下鼠标左键、松开鼠标左键)
-
按下鼠标左键
-
延迟
也就是五个操作:移动鼠标、鼠标左键按下、鼠标左键松开、鼠标左键单击(由鼠标左键按下、鼠标左键松开组合而成)、延迟
另外,还包含了脚本执行的语法顺序,如下:
-
循环:循环执行某些操作
-
顺序:脚本的执行是从上到下,顺序执行的
分析完,将上面的脚本语法转为代码语言,如下:
(表达式接口,Expression)
java
/**
* 表达式接口
*/
public interface Expression {
/**
* 解释
*/
void interpret();
}
以下都是解释器,对应上述分析的操作和流程
(移动鼠标,MoveMouse)
java
/**
* 移动鼠标
*/
public class MoveMouse implements Expression {
/**
* x坐标
*/
private int x;
/**
* y坐标
*/
private int y;
public MoveMouse(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public void interpret() {
System.out.println("移动鼠标到【" + x + "," + y + "】的位置");
}
}
(鼠标左键按下,LeftKeyDown)
java
/**
* 鼠标左键按下
*/
public class LeftKeyDown implements Expression {
@Override
public void interpret() {
System.out.println("按下鼠标左键");
}
}
(鼠标左键松开,LeftKeyUp)
java
/**
* 鼠标左键松开
*/
public class LeftKeyUp implements Expression {
@Override
public void interpret() {
System.out.println("松开鼠标左键");
}
}
(鼠标左键单击,LeftKeyClick)
java
/**
* 鼠标左键单击
*/
public class LeftKeyClick implements Expression {
/**
* 左键按下
*/
private Expression leftKeyDown;
/**
* 左键松开
*/
private Expression leftKeyUp;
/**
* 左键按下
*/
public LeftKeyClick() {
this.leftKeyDown = new LeftKeyDown();
this.leftKeyUp = new LeftKeyUp();
}
/**
* 单击鼠标左键就是先按下鼠标左键, 再松开鼠标左键
*/
@Override
public void interpret() {
leftKeyDown.interpret();
leftKeyUp.interpret();
}
}
(延迟,Delay)
java
/**
* 延迟解释器
*/
public class Delay implements Expression {
/**
* 延迟秒数
*/
private int seconds;
public Delay(int seconds) {
this.seconds = seconds;
}
public int getSeconds() {
return seconds;
}
@Override
public void interpret() {
System.out.println("系统延迟:" + seconds + "秒");
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
(循环,Repetition)
java
/**
* 循环表达式解释器
*/
public class Repetition implements Expression {
/**
* 循环次数
*/
private int loopCount;
/**
* 循环体内的表达式
*/
private Expression loopBodySequence;
public Repetition(Expression loopBodySequence, int loopCount) {
this.loopBodySequence = loopBodySequence;
this.loopCount = loopCount;
}
@Override
public void interpret() {
while (loopCount > 0) {
loopBodySequence.interpret();
loopCount--;
}
}
}
(顺序,Sequence)
java
import java.util.List;
/**
* 顺序
*/
public class Sequence implements Expression {
/**
* 脚本包含了多个表达式
*/
private List<Expression> expressions;
public Sequence(List<Expression> expressions) {
this.expressions = expressions;
}
/**
* 顺序执行表达式
*/
@Override
public void interpret() {
for (Expression expression : expressions) {
expression.interpret();
}
}
}
客户端使用,将开头的脚本按照规则放入,并解释(为了节约时间,将最后的延迟时间换成10秒)
java
import java.util.Arrays;
public class Client {
public static void main(String[] args) {
new Sequence(Arrays.asList(
new MoveMouse(500, 600),
new Repetition(
new Sequence(
Arrays.asList(
new LeftKeyClick(), new Delay(1)
)
), 5
),
new LeftKeyDown(),
new Delay(10)
)).interpret();
}
}
执行,可见每一个表达式都被成功解释

代码看下来,我认为解释器模式结构上很简单,就是定义一个接口,生成多个解释器实现类,具体的实现逻辑需要根据实际的业务实现。
使用场景
在《设计模式就该这样学》(P386)这本书中,提到解释器模式适用于以下场景:
(1)一些重复出现的问题可以用一种简单的语言进行表示。
(2)一个简单语法需要解释的场景。
例如,项目中需要解析cron表达式,根据解析后的内容去做相应的业务,我想可以考虑使用解释器模式。
总结
本文介绍了行为型设计模式中的访问者模式,参考《设计模式就该这样学》、《秒懂设计模式》两书,自定义脚本是《秒懂设计模式》中的举例。