私は初心者のプログラマーです。電卓プロジェクト用に2つのクラス図を描きます。それらのそれぞれをチェックして、どちらが良いかを教えてください。また、間違っている、または可能性のある部分を指摘していただければ幸いです。より良い。
上から始めましょう。入力文字列を受け取り、それを式の抽象構文ツリーに変換できるCalculator
が必要です。字句解析の詳細については触れませんが、複合パターンはこれに適していると結論付けることができます。
コンポジットパターンの場合、まず、あなたよりも少し一般的なExpression
インターフェイスを定義します。
interface Expression {
double evaluate();
}
複合パターンの考え方は、どのExpression
もより多くのExpression
オブジェクトを保持できるということです。これにより、レクサー/パーサーは、単一のルート式を含む式のAST=を構築できます。例:
// Don't mind the shorthand notation for brevity
Expression expr = constructAst("4 + 2 * 5") // AddExpr(4, MultExpr(2, 5));
// Evalutes 2 * 5 and then 4 + that result
expr.evaluate();
複数の式をネストできるようにするには、BinaryExpression
が2つのdoubleを操作するのではなく、2つの式を保持する必要があります。
abstract class BinaryExpression implements Expression {
private Expression left;
private Expression right;
public BinaryExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public double evaluate() {
evaluate(left.evaluate(), right.evaluate());
}
abstract protected double evaluate(double left, double right);
}
ただし、このアプローチでは、数値の式を定義する必要があります。
class NumberExpression implements Expression {
private double number;
public NumberExpression(double number) {
this.number = number;
}
public double evaluate() {
return (double) number;
}
}
パーサーでは、整数をdoubleにキャストしてNumberExpression
を再利用できます。
その後、次のように新しいバイナリ式を簡単に定義できます。
class AdditionExpression extends BinaryExpression {
protected double evaluate(double left, double right) {
return left + right;
}
}
ただし、必要に応じて、他の多くの式を定義することもできます。
class LogarithmExpression implements Expression [
private Expression operand;
public LogarithmExpression(Expression operand) {
this.operand = operand;
}
public double evaluate() {
return Math.log(operand.evaluate());
}
}
class NegateExpression implements Expression {
private Expression operand;
public NegateExpression(Expression operand) {
this.operand = operand;
}
public double evaluate() {
return -operand.evaluate();
}
}
レクサー/パーサーの複雑な実装の詳細をスキップすると、計算機は次のようになります。
class Calculator {
public double calculate(string expression) {
calculate(parseExpressionToAST(expression));
}
public double calculate(Expression expression) {
return expression.evaluate();
}
}
double twentyTwo = Calculator::calculate("2 + 4 * 5");
// This should be the same as the above calculation, since
// this is the AST of expressions that should be built by the
// lexer/parser
double twentyTwoAsWell = Calculator.calculate(new AdditionExpression(
new NumberExpression(2),
new MultiplicationExpression(
new NumberExpression(4),
new NumberExpression(5)
)
));
注:演算子の優先順位などの重要なものは、レクサー/パーサーで処理できます。