设计模式--行为模式--解释器模式
参考:https://www.cnblogs.com/adamjwh/p/10938852.html
设计模式--解释器模式(Interpreter)
这篇文章写起来比较费劲,看了大家的对解释器模式的理解,到现在还是没有摸透它的精髓,先记录下来。
一、据说设计器模式用的少,原因是:
1、执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
2、会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
3、可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
二、那它的好处到底是什么:
扩展性好(只有是模式,我感觉都可以这么说),好像就这一个缺点。
三、整体抽象的理解
1. 模式的结构:解释器模式包含以下主要角色。
A、抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法interpret()。
B、终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
C、非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
D、环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
E、客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
2. 代码
A、抽象表达式(Abstract Expression)
1 package comm.pattern.action.interpreter.basic; 2 3 import comm.pattern.action.interpreter.demo2.Context; 4 5 /** 6 * 7 * @Title: IExpressionBasic.java 8 * @Package: comm.pattern.action.interpreter.basic 9 * @Description: 抽象表达式接口 10 * @author yangzhancheng 11 * @2020年2月22日:下午10:43:05 12 * 13 */ 14 public interface IExpressionBasic { 15 16 //需要处理的方式 17 Object interpreter(ContextBasic context); 18 19 }
B、终结符表达式(Terminal Expression)
1 package comm.pattern.action.interpreter.basic; 2 3 4 /** 5 * 6 * @Title: TerminalExpression.java 7 * @Package: comm.pattern.action.interpreter 8 * @Description: 终结处理符合 9 * @author yangzhancheng 10 * @2020年2月22日:下午2:00:41 11 * 12 */ 13 public class TerminalExpressionBasic implements IExpressionBasic { 14 15 16 @Override 17 public Object interpreter(ContextBasic context) { 18 // TODO Auto-generated method stub 19 System.out.println("终结符处理!"); 20 return null; 21 } 22 23 24 25 }
C、非终结符表达式(Nonterminal Expression)
1 package comm.pattern.action.interpreter.basic; 2 3 import comm.pattern.action.interpreter.demo2.Context; 4 5 /** 6 * 7 * @Title: NonTerminalExpression.java 8 * @Package: comm.pattern.action.interpreter 9 * @Description: 非终结处理符 10 * @author yangzhancheng 11 * @2020年2月22日:下午2:07:48 12 * 13 */ 14 public class NonTerminalExpressionBasic implements IExpressionBasic { 15 16 17 @Override 18 public Object interpreter(ContextBasic context) { 19 System.out.println("非终结处理->"); 20 21 return null; 22 } 23 24 }
D、环境(Context)
1 package comm.pattern.action.interpreter.basic; 2 3 /** 4 * 5 * @Title: Context.java 6 * @Package: comm.pattern.action.interpreter 7 * @Description: 环境处理 8 * @author yangzhancheng 9 * @2020年2月22日:下午1:49:12 10 * 11 */ 12 public class ContextBasic { 13 14 15 16 }
E、客户端(Client)
1 package comm.pattern.action.interpreter.basic; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * 8 * @Title: ClientBasic.java 9 * @Package: comm.pattern.action.interpreter.basic 10 * @Description: Client客户端 11 * @author yangzhancheng 12 * @2020年2月22日:下午10:52:15 13 * 14 */ 15 public class ClientBasic { 16 17 public static void main(String[] args) { 18 19 ContextBasic context = new ContextBasic(); 20 21 List<IExpressionBasic> listBasic = new ArrayList<>(); 22 listBasic.add(new NonTerminalExpressionBasic()); 23 listBasic.add(new TerminalExpressionBasic()); 24 listBasic.add(new NonTerminalExpressionBasic()); 25 listBasic.add(new NonTerminalExpressionBasic()); 26 27 for (IExpressionBasic expressionBasic : listBasic) { 28 expressionBasic.interpreter(context); 29 } 30 } 31 32 }
以上是解释器模式的一个大的架构,细微变化或者使用,随着场景使用,略有不同。
四、实践(一):这个好像是一个变种,利用终结符表达式的多变完成。(写的有点糙,后期优化)
A、抽象表达式(Abstract Expression)
1 package comm.pattern.action.interpreter.demo1; 2 3 /** 4 * 5 * @Title: Expression.java 6 * @Package: comm.pattern.action.interpreter.demo1 7 * @Description: 抽象表达式接口 8 * @author yangzhancheng 9 * @2020年2月23日:下午3:01:09 10 * 11 */ 12 public interface Expression { 13 14 boolean interpreter(Context context); 15 }
B、终结符表达式(Terminal Expression)
1 package comm.pattern.action.interpreter.demo1; 2 /** 3 * 4 * @Title: TerminalExpression.java 5 * @Package: comm.pattern.action.interpreter.demo1 6 * @Description: 终端符合描述 7 * @author yangzhancheng 8 * @2020年2月23日:下午3:02:35 9 * 10 */ 11 public class TerminalExpression implements Expression { 12 13 private String variable ; 14 15 public TerminalExpression(String s){ 16 this.variable = s; 17 } 18 19 @Override 20 public boolean interpreter(Context context) { 21 22 int intindex = context.getMessage().indexOf(variable); 23 if(intindex >= 0){ 24 return true; 25 } 26 return false; 27 } 28 29 }
C、非终结符表达式(Nonterminal Expression)
1 package comm.pattern.action.interpreter.demo1; 2 3 /** 4 * 5 * @Title: NonTerminalExpression.java 6 * @Package: comm.pattern.action.interpreter.demo1 7 * @Description: 描述该文件做什么 8 * @author yangzhancheng 9 * @2020年2月23日:下午3:02:13 10 * 11 */ 12 public class NonTerminalExpression implements Expression { 13 14 Expression e1, e2; 15 16 public NonTerminalExpression(Expression e1, Expression e2) { 17 this.e1 = e1; 18 this.e2 = e2; 19 } 20 21 @Override 22 public boolean interpreter(Context context) { 23 // TODO Auto-generated method stub 24 return ( this.e1.interpreter(context) && this.e2.interpreter(context)); 25 } 26 27 }
D、环境(Context)
1 package comm.pattern.action.interpreter.demo1; 2 3 /** 4 * 5 * @Title: Context.java 6 * @Package: comm.pattern.action.interpreter.demo1 7 * @Description: 描述该文件做什么 8 * @author yangzhancheng 9 * @2020年2月23日:下午3:41:31 10 * 11 */ 12 public class Context { 13 14 private String message = null; 15 16 public String getMessage() { 17 return message; 18 } 19 20 public void setMessage(String message) { 21 this.message = message; 22 } 23 24 }
E、客户端(Client)
1 package comm.pattern.action.interpreter.demo1; 2 3 /** 4 * 5 * @Title: Client.java 6 * @Package: comm.pattern.action.interpreter 7 * @Description: 描述该文件做什么 8 * @author yangzhancheng 9 * @2020年2月22日:下午2:19:16 10 * 11 */ 12 public class Client { 13 14 public static void main(String[] args) { 15 16 Expression city = new TerminalExpression("湖北"); 17 Expression personn = new TerminalExpression("体温高"); 18 19 //模拟一个不能上班的。 20 Expression nonTerminalExpression = new NonTerminalExpression(city,personn); 21 Context context = new Context(); 22 context.setMessage("小黑是湖北来的,体温高"); 23 boolean isWork = nonTerminalExpression.interpreter(context); 24 if(isWork){ 25 System.out.println(context.getMessage()+",不能上班"); 26 }else{ 27 System.out.println(context.getMessage()+",能上班"); 28 } 29 30 //模拟一个能上班的。 31 context.setMessage("小黑是湖北来的,体温不高"); 32 isWork = nonTerminalExpression.interpreter(context); 33 if(isWork){ 34 System.out.println(context.getMessage()+",不能上班"); 35 }else{ 36 System.out.println(context.getMessage()+",能上班"); 37 } 38 } 39 40 }
运行结果
1 小黑是湖北来的,体温高,不能上班 2 小黑是湖北来的,体温不高,能上班
以上是一个比较糙的例子。
五、实际(二):这是一个正确的用法。
A、表达式终结符,用来统一终结与非终结表达符的业务处理逻辑。
1 package comm.pattern.action.interpreter.demo2; 2 3 /** 4 * 5 * @Title: Expression.java 6 * @Package: comm.pattern.action.interpreter.demo2 7 * @Description: 表达式终结符 8 * @author yangzhancheng 9 * @2020年2月27日:下午8:26:42 10 * 11 */ 12 13 public interface Expression { 14 15 int interpreter(Context context); 16 }
B、终结表达符业务逻辑。
1 package comm.pattern.action.interpreter.demo2; 2 3 import java.util.HashMap; 4 5 /** 6 * 7 * @Title: TerminalExpression.java 8 * @Package: comm.pattern.action.interpreter.demo2 9 * @Description: 终结符表达式 10 * @author yangzhancheng 11 * @2020年2月27日:下午8:27:13 12 * 13 */ 14 15 public class TerminalExpression implements Expression { 16 17 private String variable ; 18 19 public TerminalExpression(String variable){ 20 this.variable = variable; 21 } 22 23 @Override 24 public int interpreter(Context context) { 25 HashMap<String, Integer> intVariable = context.getVarMap(); 26 return intVariable.get(variable); 27 } 28 }
C、非终结表达符业务逻辑-加法。
1 package comm.pattern.action.interpreter.demo2; 2 3 /** 4 * 5 * @Title: AddOperation.java 6 * @Package: comm.pattern.action.interpreter.demo2 7 * @Description: 加法非终结符合 8 * @author yangzhancheng 9 * @2020年2月27日:下午8:26:04 10 * 11 */ 12 public class AddOperation implements Expression { 13 14 Expression e1, e2; 15 16 public AddOperation(Expression e1, Expression e2) { 17 this.e1 = e1; 18 this.e2 = e2; 19 } 20 21 @Override 22 public int interpreter(Context context) { 23 return this.e1.interpreter(context) + this.e2.interpreter(context); 24 } 25 26 }
D、非终结表达符业务逻辑-减法。
1 package comm.pattern.action.interpreter.demo2; 2 3 /** 4 * 5 * @Title: SubOperation.java 6 * @Package: comm.pattern.action.interpreter.demo2 7 * @Description: 减法非终结符合 8 * @author yangzhancheng 9 * @2020年2月27日:下午8:26:56 10 * 11 */ 12 public class SubOperation implements Expression{ 13 14 Expression e1, e2; 15 16 public SubOperation(Expression e1, Expression e2) { 17 this.e1 = e1; 18 this.e2 = e2; 19 } 20 21 @Override 22 public int interpreter(Context context) { 23 return this.e1.interpreter(context) - this.e2.interpreter(context); 24 } 25 26 27 }
E、上下环境类,主要用于构建表达式,并用于构建解释处理逻辑。
1 package comm.pattern.action.interpreter.demo2; 2 3 import java.util.HashMap; 4 import java.util.Stack; 5 6 /** 7 * 8 * @Title: Context.java 9 * @Package: comm.pattern.action.interpreter.demo2 10 * @Description: 上下文表达式 11 * @author yangzhancheng 12 * @2020年2月27日:下午8:26:28 13 * 14 */ 15 public class Context { 16 17 //定义表达式 18 private Expression expression; 19 //定义输入的数据 20 private HashMap<String,Integer> varMap = new HashMap<String,Integer>(); 21 22 public HashMap<String, Integer> getVarMap() { 23 return varMap; 24 } 25 26 public void setVarMap(HashMap<String, Integer> varMap) { 27 this.varMap = varMap; 28 } 29 30 31 //根据字符构造Expression函数 32 public void loopUpExpression(String expStr) { 33 //安排运算先后顺序 34 Stack<Expression> stack = new Stack<>(); 35 //表达式拆分为字符数组 36 char[] charArray = expStr.toCharArray(); 37 38 Expression left = null; 39 Expression right = null; 40 for(int i=0; i<charArray.length; i++) { 41 switch (charArray[i]) { 42 //加法 43 case '+': 44 left = stack.pop(); 45 right = new TerminalExpression(String.valueOf(charArray[++i])); 46 stack.push(new AddOperation(left, right)); 47 break; 48 //减法 49 case '-': 50 left = stack.pop(); 51 right = new TerminalExpression(String.valueOf(charArray[++i])); 52 stack.push(new SubOperation(left, right)); 53 break; 54 //公式中的变量 55 default: 56 stack.push(new TerminalExpression(String.valueOf(charArray[i]))); 57 break; 58 } 59 } 60 this.expression = stack.pop(); 61 } 62 63 //计算 64 public int run() { 65 return this.expression.interpreter(this); 66 } 67 68 }
F、用户处理程序,用户录入数据。
1 package comm.pattern.action.interpreter.demo2; 2 3 import java.io.BufferedReader; 4 import java.io.InputStreamReader; 5 import java.util.HashMap; 6 7 /** 8 * 9 * @Title: Client.java 10 * @Package: comm.pattern.action.interpreter.demo2 11 * @Description: 客户端 12 * @author yangzhancheng 13 * @2020年2月27日:下午8:26:15 14 * 15 */ 16 public class Client { 17 18 public static void main(String[] args) throws Exception { 19 20 //1.读取字符串,获取表达式 21 System.out.print("请输入表达式:"); 22 String expStr = new BufferedReader(new InputStreamReader(System.in)).readLine(); 23 24 //2.存放字符对对应的数据 25 HashMap<String, Integer> expMap = new HashMap<>(); 26 27 for(char ch : expStr.toCharArray()) { 28 if(ch != '+' && ch != '-' ) { 29 if(! expMap.containsKey(String.valueOf(ch))) { 30 System.out.print("请输入" + String.valueOf(ch) + "的值:"); 31 String in = (new BufferedReader(new InputStreamReader(System.in))).readLine(); 32 expMap.put(String.valueOf(ch), Integer.valueOf(in)); 33 } 34 } 35 } 36 37 //3.计算运行结果 38 Context context = new Context(); 39 context.loopUpExpression(expStr); 40 context.setVarMap(expMap); 41 System.out.println("运算结果:" + expStr + "=" + context.run()); 42 } 43 44 45 }
输出如下--->
请输入表达式:a+b-c 请输入a的值:24 请输入b的值:25 请输入c的值:5 运算结果:a+b-c=44
浙公网安备 33010602011771号