解释器模式的一个应用
来源:互联网 发布:农村淘宝政府如何补贴 编辑:程序博客网 时间:2024/05/22 04:49
需求
做产品的时候,有一个需求:对于一个字符串要在提交之前做校验,但是校验标准需要可配置。最合理的方案就是使用正则表达式+表达式组合。
基础数据结构
配置的数据结构如下
package com.example.ayizty.myapplication.reg;import java.util.HashMap;public class Configure { public HashMap<String, String> statements;//variant list public String expression;//separate all operand by space public HashMap<String, String> extras;}
解释器分为:
- 取非:读下一个值,并取非
- 合:对前后两值取和
- 或:对前后两值取或
- 左括号:计算后面所有值,直到遇到右括号
- 右括号:返回前一个值
- 正则表达式:计算值
- 值:布尔值,表示中间结果
expression是由!、&、|、括号和正则表达式组成的逻辑表达式,所有单词用空格分隔开。正则表达式由变量表示,对应放到statements里。(主要是懒得做词法分析)
逻辑
这是一个标准的解释器模式的应用场景,但是,因为面试题的余孽(逆波兰式,表达式解析什么的),用解释器的模式做解释器不太容易,百度最高的就是用堆栈处理表达式,然后调解释器,这就成了strategy,而不是解释器。
解释器模式的精髓在于使用函数调用的堆栈来遍历表达式树,每个解释器仅对其前后的解释器有感知,对于所有解释器都是调用interpret(为了省事,我这里特殊处理了值解释器)。
解释器基类
package com.example.ayizty.myapplication.reg;public abstract class AbsOperator { public static AbsOperator getOperand(String rawOperand, Processor processor) { switch (rawOperand.charAt(0)) { case '!': return new NegativeOperator(); case '&': return new AndOperator(); case '(': return new LeftParenthesisOperator(); case '|': return new OrOperator(); case ')': return new RightParenthesisOperator(); default: return new RegOperand(rawOperand, processor); } } public abstract ValueOperand interpret(String input, Processor processor, int index);}
解释器们
- 取非
package com.example.ayizty.myapplication.reg;public class NegativeOperand extends AbsOperand { @Override public ValueOperand interpret(String input, Processor processor, int index) { processor.removeOperand(index); AbsOperand next = processor.getOperand(index); ValueOperand result = next.interpret(input, processor, index); result.setValue(!result.getValue()); return result; } @Override public String toString() { return "!"; }}
- 合
package com.example.ayizty.myapplication.reg;public class AndOperator extends AbsOperator { @Override public ValueOperand interpret(String input, Processor processor, int index) { ValueOperand left = (ValueOperand) processor.removeOperand(index - 1); processor.removeOperand(index - 1); AbsOperator next = processor.getOperand(index - 1); return new ValueOperand(next.interpret(input, processor, index - 1).getValue() && left.getValue()); } @Override public String toString() { return "&&"; }}
- 或
package com.example.ayizty.myapplication.reg;public class OrOperator extends AbsOperator { @Override public ValueOperand interpret(String input, Processor processor, int index) { ValueOperand left = (ValueOperand) processor.removeOperand(index - 1); processor.removeOperand(index - 1); AbsOperator next = processor.getOperand(index - 1); return new ValueOperand(next.interpret(input, processor, index - 1).getValue() || left.getValue()); } @Override public String toString() { return "||"; }}
- 左括号
package com.example.ayizty.myapplication.reg;public class LeftParenthesisOperator extends AbsOperator { @Override public ValueOperand interpret(String input, Processor processor, int index) { processor.removeOperand(index); AbsOperator expected = null; do { AbsOperator next = processor.getOperand(index); processor.putOperand(index, next.interpret(input, processor, index)); expected = processor.getOperand(index + 1); } while (!(expected instanceof RightParenthesisOperator)); return expected.interpret(input, processor, index + 1); } @Override public String toString() { return "("; }}
- 右括号
public class RightParenthesisOperator extends AbsOperator { @Override public ValueOperand interpret(String input, Processor processor, int index) { ValueOperand operand = (ValueOperand) processor.removeOperand(index - 1); processor.removeOperand(index - 1); return operand; } @Override public String toString() { return ")"; }}
- 正则表达式
public class RegOperand extends AbsOperator { private Pattern mPattern; public RegOperand(String rawOperand, Processor processor) { mPattern = Pattern.compile(processor.getRawStatement(rawOperand)); } @Override public ValueOperand interpret(String input, Processor processor, int index) { processor.removeOperand(index); Matcher matcher = mPattern.matcher(input); ValueOperand result = new ValueOperand(matcher.find()); System.out.println(index + " " + this + " 3 " + result); return result; } @Override public String toString() { return mPattern.toString(); }}
- 值
public class ValueOperand extends AbsOperator { private boolean mValue; public ValueOperand(boolean value) { mValue = value; } @Override public ValueOperand interpret(String input, Processor processor, int index) { AbsOperator next = processor.getOperand(index + 1); return next.interpret(input, processor, index + 1); } public void setValue(boolean value) { mValue = value; } public boolean getValue() { return mValue; } @Override public String toString() { return String.valueOf(mValue); }}
值之所以有这个intercept是因为整体流程的需要。主要就是Processor的结构:
package com.example.ayizty.myapplication.reg;import java.util.ArrayList;public class Processor { private Configure mConfigure; private ArrayList<AbsOperator> mOperands; public Processor(Configure configure) { mConfigure = configure; String expression = configure.expression; String[] rawOperands = expression.split(" "); final int length = rawOperands.length; mOperands = new ArrayList<>(); for (int i = 0; i < length; ++i) { mOperands.add(AbsOperator.getOperand(rawOperands[i], this)); } System.out.println("init " + this); } public AbsOperator removeOperand(int index) { return mOperands.remove(index); } public AbsOperator getOperand(int index) { return mOperands.get(index); } public void putOperand(int i, AbsOperator operand) { mOperands.add(i, operand); } public String getRawStatement(String name) { return mConfigure.statements.get(name); } public boolean process(String input) { while (1 != mOperands.size()) { ValueOperand operand = mOperands.get(0).interpret(input, this, 0); mOperands.add(0, operand); System.out.println("processor " + this); } AbsOperator operand = mOperands.get(0); if (operand instanceof ValueOperand) { return ((ValueOperand) operand).getValue(); } return false; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); final int length = mOperands.size(); for (int i = 0; i < length; ++i) { stringBuilder.append(mOperands.get(i)); } return stringBuilder.toString(); }}
这里就是解释器模式的整体调用逻辑,没有树、没有堆栈,简单到底的对第一个解释器进行解释。
PS
解释器模式确实让代码简单的令人发指,但是有一些问题:
- 类爆炸,简简单单的逻辑表达式已经10个类了,而且每个类都非常简单
- 过多的对象,每次运行都会产生大量中间变量,固然是很不好的。可以使用对象池+工厂解决。
0 0
- 解释器模式的一个应用
- 解释器模式的一个简单示例
- 设计模式的应用场景(23)--解释器模式
- android设计模式应用--解释器模式
- 一天一个设计模式---解释器模式
- 一个23设计模式的搞笑解释
- 一个23设计模式的搞笑解释
- Android的设计模式-解释器模式
- python解释器实现及其嵌入式应用:一个四则运算计算器的实现
- 解释器模式--注重的解释的思想
- 一个Command模式的应用例子
- .net 未来的一个应用模式
- 原始的解释器模式(Interpreter Pattern)
- 解释器模式的简单使用
- 一个命令解释器的源代码
- 写一个brainfuck语言的解释器
- 一个简易的Scheme解释器
- 一个触发器的解释
- HDU5510Bazinga(暴力剪枝)
- 大数据环境下的云计算与物联网
- flash乱码解决方案
- linux 内核链表(二)
- Android四大组件之Activity
- 解释器模式的一个应用
- 【LEETCODE】108-Convert Sorted Array to Binary Search Tree
- hdu5372Segment Game 树状数组
- LeetCode---Plus One
- javascript的prototype实现回调
- 不要把配置文件放到你的Git代码仓库
- linux 内核链表( 四 )
- 线程的创建 以及 线程的各种状态
- C++Primer之复合类型