打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
解释器模式——定义一种简单的语言

一 模式定义

解释器模式:就是给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子。解释器模式描述了怎样在有了一个简单的文法后,使用模式设计解释这些语句。

 

二模式举例

1 模式分析

我们自己设计一种语言来说明这一模式

(1)该语言区分大小写

(2)该语言以PROGRAM开头,END结尾

(3)PRINTLN表示打印一行并换行

(4)使用FOR…FROM…TO…END表示循环

示例语言内容如下:

PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end...END

该句表示的意思是:首先打印“start…”换行,然后循环打印“90”换行、“91”换行、……“100”换行,最后打印“end…”换行。

2 该语言解释树结构



 

3 该语言解释器活动图



 

4 代码示例

4.1 创建上下文环境——Context

Java代码  
  1. package com.demo.interpreter.context;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Iterator;  
  5. import java.util.Map;  
  6. import java.util.StringTokenizer;  
  7.   
  8. /** 
  9.  * 上下文环境 
  10.  *  
  11.  * @author 
  12.  *  
  13.  */  
  14. public class Context {  
  15.     // 待解析的文本内容  
  16.     private final StringTokenizer stringTokenizer;  
  17.     // 当前命令  
  18.     private String currentToken;  
  19.     // 用来存储动态变化信息内容  
  20.     private final Map<String, Object> map = new HashMap<String, Object>();  
  21.   
  22.     /** 
  23.      * 构造方法设置解析内容 
  24.      *  
  25.      * @param text 
  26.      */  
  27.     public Context(String text) {  
  28.         // 使用空格分隔待解析文本内容  
  29.         this.stringTokenizer = new StringTokenizer(text);  
  30.     }  
  31.   
  32.     /** 
  33.      * 解析文本 
  34.      */  
  35.     public String next() {  
  36.         if (this.stringTokenizer.hasMoreTokens()) {  
  37.             currentToken = this.stringTokenizer.nextToken();  
  38.         } else {  
  39.             currentToken = null;  
  40.         }  
  41.         return currentToken;  
  42.     }  
  43.   
  44.     /** 
  45.      * 判断命令是否正确 
  46.      *  
  47.      * @param command 
  48.      * @return 
  49.      */  
  50.     public boolean equalsWithCommand(String command) {  
  51.         if (command == null || !command.equals(this.currentToken)) {  
  52.             return false;  
  53.         }  
  54.         return true;  
  55.     }  
  56.   
  57.     /** 
  58.      * 获得当前命令内容 
  59.      *  
  60.      * @return 
  61.      */  
  62.     public String getCurrentToken() {  
  63.         return this.currentToken;  
  64.     }  
  65.   
  66.     /** 
  67.      * 获得节点的内容 
  68.      *  
  69.      * @return 
  70.      */  
  71.     public String getTokenContent(String text) {  
  72.   
  73.         String str = text;  
  74.         if (str != null) { // 替换map中的动态变化内容后返回 Iterator<String>  
  75.             // 替换map中的动态变化内容后返回  
  76.             Iterator<String> iterator = this.map.keySet().iterator();  
  77.   
  78.             while (iterator.hasNext()) {  
  79.                 String key = iterator.next();  
  80.                 Object obj = map.get(key);  
  81.                 str = str.replaceAll(key, obj.toString());  
  82.             }  
  83.         }  
  84.   
  85.         return str;  
  86.     }  
  87.   
  88.     public void put(String key, Object value) {  
  89.         this.map.put(key, value);  
  90.     }  
  91.   
  92.     public void clear(String key) {  
  93.         this.map.remove(key);  
  94.     }  
  95.   
  96. }  

 

4.2 表达式接口——IExpressions

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import com.demo.interpreter.context.Context;  
  4.   
  5. /** 
  6.  *  
  7.  * 表达式接口 
  8.  *  
  9.  * @author 
  10.  *  
  11.  */  
  12. public interface IExpressions {  
  13.   
  14.     /** 
  15.      * 解析 
  16.      *  
  17.      * @param context 
  18.      */  
  19.     public void parse(Context context);  
  20.   
  21.     /** 
  22.      * 执行方法 
  23.      *  
  24.      * @param context 
  25.      */  
  26.     public void interpret();  
  27. }  

 

4.3 主表达式——ProgramExpression

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import com.demo.interpreter.context.Context;  
  4.   
  5. /** 
  6.  * program 表达式 
  7.  *  
  8.  * @author 
  9.  *  
  10.  */  
  11. public class ProgramExpression implements IExpressions {  
  12.   
  13.     // 上下文环境  
  14.     private final Context context;  
  15.     // 当前命令  
  16.     private final static String COMMAND = "PROGRAM";  
  17.   
  18.     // 存储下一个表达式引用  
  19.     private IExpressions expressions;  
  20.   
  21.     /** 
  22.      * 构造方法将待解析的内容传入 
  23.      *  
  24.      * @param text 
  25.      */  
  26.     public ProgramExpression(String text) {  
  27.         this.context = new Context(text);  
  28.         this.parse(this.context);  
  29.     }  
  30.   
  31.     @Override  
  32.     public void parse(Context context) {  
  33.         // 获取第一个命令节点  
  34.         this.context.next();  
  35.     }  
  36.   
  37.     /** 
  38.      * 实现解释方法 
  39.      */  
  40.     @Override  
  41.     public void interpret() {  
  42.   
  43.         // 判断是否是以PROGRAM 开始  
  44.         if (!this.context.equalsWithCommand(COMMAND)) {  
  45.             System.out.println("The '" + COMMAND + "' is Excepted For Start!");  
  46.         } else {  
  47.             // 是以PROGRAM 开始  
  48.             this.context.next();  
  49.             this.expressions = new ListExpression();  
  50.             this.expressions.parse(this.context);  
  51.             // ListExpression表达式开始解析  
  52.             this.expressions.interpret();  
  53.         }  
  54.     }  
  55.   
  56. }  

 

4.4 列表表达式——ListExpression

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Iterator;  
  5.   
  6. import com.demo.interpreter.context.Context;  
  7.   
  8. /** 
  9.  * 列表表达式 
  10.  *  
  11.  * @author 
  12.  *  
  13.  */  
  14. public class ListExpression implements IExpressions {  
  15.   
  16.     private Context context;  
  17.   
  18.     private final ArrayList<IExpressions> list = new ArrayList<IExpressions>();  
  19.   
  20.     /** 
  21.      * 构造方法将待解析的context传入 
  22.      *  
  23.      * @param context 
  24.      */  
  25.   
  26.     public void parse(Context context) {  
  27.         this.context = context;  
  28.         // 在ListExpression解析表达式中,循环解释语句中的每一个单词,直到终结符表达式或者异常情况退出  
  29.         while (true) {  
  30.             if (this.context.getCurrentToken() == null) {  
  31.                 // 获取当前节点如果为 null 则表示缺少END表达式  
  32.                 System.out.println("Error: The Experssion Missing 'END'! ");  
  33.                 break;  
  34.             } else if (this.context.equalsWithCommand("END")) {  
  35.                 this.context.next();  
  36.                 // 解析正常结束  
  37.                 break;  
  38.   
  39.             } else {  
  40.   
  41.                 // 建立Command 表达式  
  42.                 IExpressions expressions = new CommandExperssion(this.context);  
  43.                 // 添加到列表中  
  44.                 list.add(expressions);  
  45.             }  
  46.         }  
  47.     }  
  48.   
  49.     /** 
  50.      * 实现解释方法 
  51.      */  
  52.     @Override  
  53.     public void interpret() {  
  54.         // 循环list列表中每一个表达式 解释执行  
  55.         Iterator<IExpressions> iterator = list.iterator();  
  56.         while (iterator.hasNext()) {  
  57.             (iterator.next()).interpret();  
  58.         }  
  59.     }  
  60. }  

 

4.5 命令表达式——CommandExperssion

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import com.demo.interpreter.context.Context;  
  4.   
  5. /** 
  6.  * 命令表达式 
  7.  *  
  8.  * @author 
  9.  *  
  10.  */  
  11. public class CommandExperssion implements IExpressions {  
  12.     private final Context context;  
  13.     private IExpressions expressions;  
  14.   
  15.     /** 
  16.      * 构造方法将待解析的context传入 
  17.      *  
  18.      * @param context 
  19.      */  
  20.     public CommandExperssion(Context context) {  
  21.         this.context = context;  
  22.         this.parse(this.context);  
  23.     }  
  24.   
  25.     public void parse(Context context) {  
  26.   
  27.         // 判断当前命令类别 在此只对For和最原始命令进行区分  
  28.         if (this.context.equalsWithCommand("FOR")) {  
  29.             // 创建For表达式进行解析  
  30.             expressions = new ForExpression(this.context);  
  31.         } else {  
  32.             // 创建原始命令表达式进行内容解析  
  33.             expressions = new PrimitiveExpression(this.context);  
  34.         }  
  35.     }  
  36.   
  37.     /** 
  38.      * 解析内容 
  39.      */  
  40.     @Override  
  41.     public void interpret() {  
  42.         // 解析内容  
  43.         this.expressions.interpret();  
  44.     }  
  45.   
  46. }  

 

4.6 循环表达式——ForExpression

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import com.demo.interpreter.context.Context;  
  4.   
  5. /** 
  6.  * For表达式 
  7.  *  
  8.  * @author 
  9.  *  
  10.  */  
  11. public class ForExpression implements IExpressions {  
  12.   
  13.     private final Context context;  
  14.   
  15.     // 存储当前索引key值  
  16.     private String variable;  
  17.     // 存储循环起始位置  
  18.     private int start_index;  
  19.     // 存储循环结束位置  
  20.     private int end_index;  
  21.   
  22.     private IExpressions expressions;  
  23.   
  24.     /** 
  25.      * 构造方法将待解析的context传入 
  26.      *  
  27.      * @param context 
  28.      */  
  29.     public ForExpression(Context context) {  
  30.         this.context = context;  
  31.         this.parse(this.context);  
  32.     }  
  33.   
  34.     /** 
  35.      * 解析表达式 
  36.      */  
  37.     @Override  
  38.     public void parse(Context context) {  
  39.         // 首先获取当前节点  
  40.         this.context.next();  
  41.         while (true) {  
  42.             // 判断节点  
  43.             if (this.context.equalsWithCommand("FROM")) {  
  44.                 // 设置开始索引内容  
  45.                 String nextStr = this.context.next();  
  46.                 try {  
  47.                     this.start_index = Integer.parseInt(nextStr);  
  48.                 } catch (Exception e) {  
  49.                     System.out  
  50.                             .println("Error: After 'FROM' Expression Exist Error!Please Check the Format Of Expression is Correct!");  
  51.   
  52.                     break;  
  53.                 }  
  54.                 // 获取下一个节点  
  55.                 this.context.next();  
  56.             } else if (this.context.equalsWithCommand("TO")) {  
  57.                 // 设置结束索引内容  
  58.                 String nextStr = this.context.next();  
  59.                 try {  
  60.                     this.end_index = Integer.parseInt(nextStr);  
  61.                 } catch (Exception e) {  
  62.                     System.out  
  63.                             .println("Error: After 'TO' Expression Exist Error!Please Check the Format Of Expression is Correct!");  
  64.                 }  
  65.                 this.context.next();  
  66.                 break;  
  67.             } else {  
  68.                 // 设置当前索引变量内容  
  69.                 if (this.variable == null) {  
  70.                     this.variable = this.context.getCurrentToken();  
  71.                 }  
  72.                 // 获取下一个节点  
  73.                 this.context.next();  
  74.             }  
  75.         }  
  76.         // 建立列表表达式  
  77.         this.expressions = new ListExpression();  
  78.         this.expressions.parse(this.context);  
  79.     }  
  80.   
  81.     /** 
  82.      * 实现解释方法 
  83.      */  
  84.     @Override  
  85.     public void interpret() {  
  86.         // 建立命令表达式  
  87.         for (int x = this.start_index; x <= this.end_index; x++) {  
  88.             // 设置变量内容  
  89.             this.context.put("" + this.variable, x);  
  90.             // 执行解释方法  
  91.             this.expressions.interpret();  
  92.         }  
  93.         // 移除使用的临时变量内容  
  94.         this.context.clear("" + this.variable);  
  95.     }  
  96. }  

 

4.7 基础表达式——PrimitiveExpression

Java代码  
  1. package com.demo.interpreter.express;  
  2.   
  3. import com.demo.interpreter.context.Context;  
  4.   
  5. /** 
  6.  * 最基础的表达式 
  7.  *  
  8.  * @author 
  9.  *  
  10.  */  
  11. public class PrimitiveExpression implements IExpressions {  
  12.     private Context context;  
  13.     // 节点名称  
  14.     private String tokenName;  
  15.     // 文本内容  
  16.     private String text;  
  17.   
  18.     /** 
  19.      * 构造方法将待解析的context传入 
  20.      *  
  21.      * @param context 
  22.      */  
  23.     public PrimitiveExpression(Context context) {  
  24.         this.parse(context);  
  25.     }  
  26.   
  27.     @Override  
  28.     public void parse(Context context) {  
  29.         this.context = context;  
  30.         this.tokenName = this.context.getCurrentToken();  
  31.         this.context.next();  
  32.         if ("PRINTLN".equals(this.tokenName)) {  
  33.             this.text = this.context.getCurrentToken();  
  34.             this.context.next();  
  35.         }  
  36.     }  
  37.   
  38.     /** 
  39.      * 实现解释方法 
  40.      */  
  41.     @Override  
  42.     public void interpret() {  
  43.         // 首先获取当前节点内容  
  44.         if ("PRINTLN".equals(tokenName)) {  
  45.             // 获得内容信息  
  46.             // 打印内容  
  47.             System.out.println(this.context.getTokenContent(this.text));  
  48.         }  
  49.     }  
  50.   
  51. }  

 

4.8 让语言解释器开始工作——Client

Java代码  
  1. package com.demo.interpreter;  
  2.   
  3. import com.demo.interpreter.express.IExpressions;  
  4. import com.demo.interpreter.express.ProgramExpression;  
  5.   
  6. /** 
  7.  * 主应用程序 
  8.  *  
  9.  * @author 
  10.  *  
  11.  */  
  12. public class Client {  
  13.   
  14.     /** 
  15.      * @param args 
  16.      */  
  17.     public static void main(String[] args) {  
  18.         // myida语言语句  
  19.         String str = "PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END";  
  20.         System.out.println("str:" + str);  
  21.         // 创建PROGRAM表达式  
  22.         IExpressions expressions = new ProgramExpression(str);  
  23.         // 解释执行  
  24.         expressions.interpret();  
  25.     }  
  26. }  

 

5 运行结果

str:PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END

start...

90

91

92

93

94

95

96

97

98

99

100

end...

 

三 设计原则

1 “开-闭”原则

2 封闭变化原则

 

四 使用场合

(1)一种特定类型的问题发生的频率足够高,并且业务规则频繁变化,不断重复出现类似情况。

(2)业务规则不是过于复杂烦琐,比较容易抽象出语法规则。

(3)效率不是软件系统中主要考虑的因素。

 

五 解释器模式静态类图



 

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
自定义语言的实现
第17章 行为型模式
通俗易懂设计模式解析——解释器模式
struts2中的ValueStack学习
大数据学习路线分享Lambda表达式
设计模式之Interpreter(解释器)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服