18.4 完整解決方案
為瞭能夠解釋機器人控制指令,Sunny軟件公司開發人員使用解釋器模式來設計和實現機器人控制程序。針對五條文法規則,分別提供五個類來實現,其中終結符表達式direction、action和distance對應DirectionNode類、ActionNode類和DistanceNode類,非終結符表達式expression和composite對應SentenceNode類和AndNode類。
我們可以通過抽象語法樹來表示具體解釋過程,例如機器人控制指令“downrun 10 and left move20”對應的抽象語法樹如圖18-4所示:
、
圖18-4 機器人控制程序抽象語法樹實例
機器人控制程序實例基本結構如圖18-5所示:
圖18-5 機器人控制程序結構圖
在圖18-5中,AbstractNode充當抽象表達式角色,DirectionNode、ActionNode和DistanceNode充當終結符表達式角色,AndNode和SentenceNode充當非終結符表達式角色。完整代碼如下所示:
[java] view plaincopy
//註:本實例對機器人控制指令的輸出結果進行模擬,將英文指令翻譯為中文指令,實際情況是調用不同的控制程序進行機器人的控制,包括對移動方向、方式和距離的控制等
import java.util.*;
//抽象表達式
abstract class AbstractNode {
public abstract String interpret();
}
//And解釋:非終結符表達式
class AndNode extends AbstractNode {
private AbstractNode left; //And的左表達式
private AbstractNode right; //And的右表達式
public AndNode(AbstractNode left, AbstractNode right) {
this.left = left;
this.right = right;
}
//And表達式解釋操作
public String interpret() {
return left.interpret() + "再" + right.interpret();
}
}
//簡單句子解釋:非終結符表達式
class SentenceNode extends AbstractNode {
private AbstractNode direction;
private AbstractNode action;
private AbstractNode distance;
public SentenceNode(AbstractNode direction,AbstractNode action,AbstractNode distance) {
this.direction = direction;
this.action = action;
this.distance = distance;
}
//簡單句子的解釋操作
public String interpret() {
return direction.interpret() + action.interpret() + distance.interpret();
}
}
//方向解釋:終結符表達式
class DirectionNode extends AbstractNode {
private String direction;
public DirectionNode(String direction) {
this.direction = direction;
}
//方向表達式的解釋操作
public String interpret() {
if (direction.equalsIgnoreCase("up")) {
return "向上";
}
else if (direction.equalsIgnoreCase("down")) {
return "向下";
}
else if (direction.equalsIgnoreCase("left")) {
return "向左";
}
else if (direction.equalsIgnoreCase("right")) {
return "向右";
}
else {
return "無效指令";
}
}
}
//動作解釋:終結符表達式
class ActionNode extends AbstractNode {
private String action;
public ActionNode(String action) {
this.action = action;
}
//動作(移動方式)表達式的解釋操作
public String interpret() {
if (action.equalsIgnoreCase("move")) {
return "移動";
}
else if (action.equalsIgnoreCase("run")) {
return "快速移動";
}
else {
return "無效指令";
}
}
}
//距離解釋:終結符表達式
class DistanceNode extends AbstractNode {
private String distance;
public DistanceNode(String distance) {
this.distance = distance;
}
//距離表達式的解釋操作
public String interpret() {
return this.distance;
}
}
//指令處理類:工具類
class InstructionHandler {
private String instruction;
private AbstractNode node;
public void handle(String instruction) {
AbstractNode left = null, right = null;
AbstractNode direction = null, action = null, distance = null;
Stack stack = new Stack(); //聲明一個棧對象用於存儲抽象語法樹
String[] words = instruction.split(" "); //以空格分隔指令字符串
for (int i = 0; i < words.length; i++) {
//本實例采用棧的方式來處理指令,如果遇到“and”,則將其後的三個單詞作為三個終結符表達式連成一個簡單句子SentenceNode作為“and”的右表達式,而將從棧頂彈出的表達式作為“and”的左表達式,最後將新的“and”表達式壓入棧中。 if (words[i].equalsIgnoreCase("and")) {
left = (AbstractNode)stack.pop(); //彈出棧頂表達式作為左表達式
String word1= words[++i];
direction = new DirectionNode(word1);
String word2 = words[++i];
action = new ActionNode(word2);
String word3 = words[++i];
distance = new DistanceNode(word3);
right = new SentenceNode(direction,action,distance); //右表達式
stack.push(new AndNode(left,right)); //將新表達式壓入棧中
}
//如果是從頭開始進行解釋,則將前三個單詞組成一個簡單句子SentenceNode並將該句子壓入棧中
else {
String word1 = words[i];
direction = new DirectionNode(word1);
String word2 = words[++i];
action = new ActionNode(word2);
String word3 = words[++i];
distance = new DistanceNode(word3);
left = new SentenceNode(direction,action,distance);
stack.push(left); //將新表達式壓入棧中
}
}
this.node = (AbstractNode)stack.pop(); //將全部表達式從棧中彈出
}
public String output() {
String result = node.interpret(); //解釋表達式
return result;
}
}
工具類InstructionHandler用於對輸入指令進行處理,將輸入指令分割為字符串數組,將第1個、第2個和第3個單詞組合成一個句子,並存入棧中;如果發現有單詞“and”,則將“and”後的第1個、第2個和第3個單詞組合成一個新的句子作為“and”的右表達式,並從棧中取出原先所存句子作為左表達式,然後組合成一個And節點存入棧中。依此類推,直到整個指令解析結束。
編寫如下客戶端測試代碼:
[java]
class Client {
public static void main(String args[]) {
String instruction = "up move 5 and down run 10 and left move 5";
InstructionHandler handler = new InstructionHandler();
handler.handle(instruction);
String outString;
outString = handler.output();
System.out.println(outString);
}
}
編譯並運行程序,輸出結果如下:
向上移動5再向下快速移動10再向左移動5
作者:劉偉