設計模式19-解釋器模式

1.場景問題解決

1.1 場景描述

大數據統計項目遇到的問題:
按照計算模型對現有數據統計、分析、預測
一般的計算模型是一個或多個運算公式,通常是加減乘除四則運算
計算模型需要運行期編輯
設計方案要有高擴展性

1.2 OO設計

1.3 需求變動

1.4 帶來問題

2.用設計模式改進

2.1 分析

計算模型按正常算術方式書寫,解釋器處理語法邏輯
計算模型裏有兩類符號:數據和計算符
用逆波蘭算法分析算式語法
用解釋器模式處理數據

2.2 重新設計

[外鏈圖片轉存失敗(img-xPyBo3Hh-1568648786773)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/19%E8%A7%A3%E9%87%8A%E5%99%A8%E6%A8%A1%E5%BC%8F-2.png)]

2.3 源碼

- cls 該包爲各種逆波蘭之後的各種計算方式
- - AbstractExpresstion 抽象類,所有的超類(HashMap<String, Float> 爲一列數據)
- - - VarExpresstion 終結表達式(變量表達式)
- - - SymbolExpresstion 非終結表達式(符號表達式,抽象類)
- - - - AddExpresstion 加
- - - - SubExpresstion 減
- - - - MultiExpresstion 乘
- - - - DivExpresstion 除


public abstract class AbstractExpresstion {
	public abstract Float interpreter(HashMap<String, Float> var);
}


public class VarExpresstion extends AbstractExpresstion {
	private String key;

	public VarExpresstion(String _key) {
		this.key = _key;
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return var.get(this.key);
	}
}

public abstract class SymbolExpresstion extends AbstractExpresstion {
	protected AbstractExpresstion left;
	protected AbstractExpresstion right;

	public SymbolExpresstion(AbstractExpresstion _left,AbstractExpresstion _right) {
		this.left = _left;
		this.right = _right;
	}
}


public class AddExpresstion extends SymbolExpresstion {
	public AddExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) + super.right.interpreter(var);
	}
}


public class SubExpresstion extends SymbolExpresstion {
	public SubExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) - super.right.interpreter(var);
	}
}



public class MultiExpresstion extends SymbolExpresstion {
	public MultiExpresstion(AbstractExpresstion _left,
			AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) * super.right.interpreter(var);
	}
}



public class DivExpresstion extends SymbolExpresstion {
	public DivExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) / super.right.interpreter(var);
	}
}




public class RPN {

	private ArrayList<String> expression = new ArrayList<String>();// 存儲中序表達式

	private ArrayList<String> right = new ArrayList<String>();// 存儲右序表達式

	private AbstractExpresstion result;// 結果

	// 依據輸入信息創建對象,將數值與操作符放入ArrayList中
	public RPN(String input) {
		StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
		while (st.hasMoreElements()) {
			expression.add(st.nextToken());
		}
	}

	// 將中序表達式轉換爲右序表達式
	private void toRight() {
		Stacks aStack = new Stacks();
		String operator;
		int position = 0;
		while (true) {
			if (Calculate.isOperator((String) expression.get(position))) {
				if (aStack.top == -1
						|| ((String) expression.get(position)).equals("(")) {
					aStack.push(expression.get(position));
				} else {
					if (((String) expression.get(position)).equals(")")) {
						if (!((String) aStack.top()).equals("(")) {
							operator = (String) aStack.pop();
							right.add(operator);
						}
					} else {
						if (Calculate.priority((String) expression
								.get(position)) <= Calculate
								.priority((String) aStack.top())
								&& aStack.top != -1) {
							operator = (String) aStack.pop();
							if (!operator.equals("("))
								right.add(operator);
						}
						aStack.push(expression.get(position));
					}
				}
			} else
				right.add(expression.get(position));
			position++;
			if (position >= expression.size())
				break;
		}
		while (aStack.top != -1) {
			operator = (String) aStack.pop();
			right.add(operator);
		}
	}

	// 對右序表達式進行求值
	public void getResult(HashMap<String, Float> var) {
		this.toRight();
		Stack<AbstractExpresstion> stack = new Stack<AbstractExpresstion>();
		AbstractExpresstion op1, op2;
		String is = null;
		Iterator it = right.iterator();

		while (it.hasNext()) {
			is = (String) it.next();
			if (Calculate.isOperator(is)) {
				op2 = stack.pop();
				op1 = stack.pop();
				stack.push(Calculate.twoResult(is, op1, op2));
			} else
				stack.push(new VarExpresstion(is));
		}
		result = stack.pop();
		it = expression.iterator();
		while (it.hasNext()) {
			System.out.print((String) it.next());
		}
		System.out.println("=" + result.interpreter(var));
	}

	public static class Calculate {
		// 判斷是否爲操作符號
		public static boolean isOperator(String operator) {
			if (operator.equals("+") || operator.equals("-")
					|| operator.equals("*") || operator.equals("/")
					|| operator.equals("(") || operator.equals(")"))
				return true;
			else
				return false;
		}

		// 設置操作符號的優先級別
		public static int priority(String operator) {
			if (operator.equals("+") || operator.equals("-")
					|| operator.equals("("))
				return 1;
			else if (operator.equals("*") || operator.equals("/"))
				return 2;
			else
				return 0;
		}

		// 做2值之間的計算
		public static AbstractExpresstion twoResult(String op,
				AbstractExpresstion a, AbstractExpresstion b) {
			try {

				AbstractExpresstion result = null;
				if (op.equals("+"))
					result = new AddExpresstion(a, b);
				else if (op.equals("-"))
					result = new SubExpresstion(a, b);
				else if (op.equals("*"))
					result = new MultiExpresstion(a, b);
				else if (op.equals("/"))
					result = new DivExpresstion(a, b);
				else
					;
				return result;
			} catch (NumberFormatException e) {
				System.out.println("input has something wrong!");
				return null;
			}
		}
	}

	// 棧類
	public class Stacks {
		private LinkedList list = new LinkedList();
		int top = -1;

		public void push(Object value) {
			top++;
			list.addFirst(value);
		}

		public Object pop() {
			Object temp = list.getFirst();
			top--;
			list.removeFirst();
			return temp;

		}

		public Object top() {
			return list.getFirst();
		}
	}
}

  • Calculator(計算),InterpreterTest(測試類)

public class Calculator {
	public Calculator() {
		float[][] dataSource = new float[3][6];
		System.out.println("data source:");
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 6; j++) {
				dataSource[i][j] = (float) (Math.random() * 100);
				System.out.print(dataSource[i][j] + ",");
			}
			System.out.println(";");
		}

		try {
			System.out.println("Input a expression:");
			BufferedReader is = new BufferedReader(new InputStreamReader(
					System.in));
			for (;;) {
				String input = new String();
				input = is.readLine().trim();
				if (input.equals("q"))
					break;
				else {
					RPN boya = new RPN(input);
					HashMap<String, Float> var;
					for (int i = 0; i < 3; i++) {
						var = new HashMap<String, Float>();
						var.put("a", dataSource[i][0]);
						var.put("b", dataSource[i][1]);
						var.put("c", dataSource[i][2]);
						var.put("d", dataSource[i][3]);
						var.put("e", dataSource[i][4]);
						var.put("f", dataSource[i][5]);

						boya.getResult(var);
					}
				}
				System.out.println("Input another expression or input 'q' to quit:");
			}
			is.close();
		} catch (IOException e) {
			System.out.println("Wrong input!!!");
		}
	}
}




public class InterpreterTest {
	public static void main(String[] args) {
		new Calculator();
	}
}

執行Test類後在控制檯輸入:a、b、c、d、e、f爲變量的包含可以±*/()的運算公式,然後回車得出結果.

3.設計模式總結

3.1 定義

解釋器模式 定義一個語法, 定義一個解釋器,該解釋器處理該語法句子
將某些複雜問題,表達爲某種語法規則,然後構建解釋器來解釋處理這類句子

3.2 分析思路

[外鏈圖片轉存失敗(img-5JGdLcbq-1568648786775)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/19%E8%A7%A3%E9%87%8A%E5%99%A8%E6%A8%A1%E5%BC%8F-1.png)]

3.3 優缺點

  • 優點
    • 容易修改,修改語法規則只要修改相應非終結符即可
    • 擴展方便,擴展語法,只要增加非終結符類即可
  • 缺點:
    • 對於複雜語法的表示會產生複雜的類層次結構,不便管理和維護
    • 解釋器採用遞歸方式,效率會受影響

4. 設計模式使用場景及注意

4.1 注意事項:

儘量不要在重要的模塊中使用解釋器模式
解釋器模式在實際的系統開發中使用的非常少
可以考慮一下Expression4J、MESP、Jep等開源的解析工具包

4.2 適用場合:

當你有一個簡單語法,而且效率不是問題的時候
一些數據分析工具、報表設計工具、科學計算工具等

5.參考文章

內容總計於HeadFirst設計模式及相關視頻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章