[Design Pattern] Verhaltensmuster: Interpreter

Thomas Darimont

Erfahrenes Mitglied
Hallo,

dieser Beitrag erklärt das Verhaltensmuster: Interpreter

Java:
package de.tutorials.design.patterns.behavioral;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

public class InterpreterExample {

	public static void main(String[] args) {
		Interpreter interpreter = new Interpreter();
		interpreter.eval("+ 3 4");
		interpreter.eval("* 6 7");
		interpreter.eval("^ 2 10");
		interpreter.eval("sqrt 9");
		interpreter.eval("cos 37");

	}

	static class Interpreter {

		public Double eval(String input) {
			Expression expression = ASTParser.INSTANCE.parse(input.trim());
			System.out.println(expression);
			Double result = eval(expression);
			System.out.println(" = " + result);
			return result;
		}

		public Double eval(Expression input) {
			if (input instanceof NumberExpression) {
				return ((NumberExpression) input).value;
			} else if (input instanceof UnaryOperation) {
				UnaryOperation uo = (UnaryOperation) input;
				switch (uo.operator) {
				case "sin":  return Math.sin(eval(uo.argument));
				case "cos":  return Math.cos(eval(uo.argument));
				case "tan":  return Math.tan(eval(uo.argument));
				case "ln":   return Math.log(eval(uo.argument));
				case "sqrt": return Math.sqrt(eval(uo.argument));
				}
			} else if (input instanceof BinaryOperation) {
				BinaryOperation bo = (BinaryOperation) input;
				switch (bo.operation) {
				case "+": return eval(bo.left) + eval(bo.right);
				case "-": return eval(bo.left) - eval(bo.right);
				case "*": return eval(bo.left) * eval(bo.right);
				case "/": return eval(bo.left) / eval(bo.right);
				case "^": return Math.pow(eval(bo.left), eval(bo.right));
				}
			}
			return Double.NaN;
		}
	}

	static abstract class Expression {}

	static class NumberExpression extends Expression {
		private final Double value;

		public NumberExpression(Double value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value.toString();
		}
	}

	static class UnaryOperation extends Expression {
		private final String operator;
		private final Expression argument;

		public UnaryOperation(String operator, Expression argument) {
			this.operator = operator;
			this.argument = argument;
		}

		@Override
		public String toString() {
			return operator + "(" + argument + ")";
		}
	}

	static class BinaryOperation extends Expression {
		private final String operation;
		private final Expression left;
		private final Expression right;

		public BinaryOperation(String operation, Expression left, Expression right) {
			this.operation = operation;
			this.left = left;
			this.right = right;
		}

		@Override
		public String toString() {
			return "(" + left + " " + operation + " " + right + ")";
		}
	}

	enum ASTParser {
		INSTANCE;

		public Expression parse(String input) {
			List<String> tokens = Arrays.asList(input.split(" "));
			Collections.reverse(tokens);
			Stack<Expression> stack = new Stack<Expression>();
			for (String token : tokens) {
				switch (token) {
				case "+":    stack.push(new BinaryOperation("+", stack.pop(), stack.pop())); break;
				case "-":    stack.push(new BinaryOperation("-", stack.pop(), stack.pop())); break;
				case "*":    stack.push(new BinaryOperation("*", stack.pop(), stack.pop())); break;
				case "/":    stack.push(new BinaryOperation("/", stack.pop(), stack.pop())); break;
				case "^":    stack.push(new BinaryOperation("^", stack.pop(), stack.pop())); break;
				case "sin":  stack.push(new UnaryOperation("sin", stack.pop())); break;
				case "cos":  stack.push(new UnaryOperation("cos", stack.pop())); break;
				case "tan":  stack.push(new UnaryOperation("tan", stack.pop())); break;
				case "sqrt": stack.push(new UnaryOperation("sqrt", stack.pop())); break;
				case "ln": 	 stack.push(new UnaryOperation("ln", stack.pop())); break;
				default: stack.push(new NumberExpression(Double.parseDouble(token)));
				}
			}
			return stack.pop();
		}
	}
}

Ausgabe:
Code:
(3.0 + 4.0)
 = 7.0
(6.0 * 7.0)
 = 42.0
(2.0 ^ 10.0)
 = 1024.0
sqrt(9.0)
 = 3.0
cos(37.0)
 = 0.7654140519453434


Gruß Tom
 
Zurück