我正在构建一个用于符号计算的java库。 我创建了一个抽象表达式类,用于在产品,分数和多项式之间进行各种操作。然而,当我想添加地板和天花板时,事情变得复杂了。我知道周围有这样的库,我想知道是否有特定的设计模式可以遵循,或者是否有任何资源我可以寻求灵感和指导。
答案 0 :(得分:2)
你最有可能正在解析一个“无上下文的语言”(Type {2,根据Chomsky hierarchy)。试着阅读http://en.wikipedia.org/wiki/LL_parser和http://en.wikipedia.org/wiki/Pushdown_automaton - 你不一定要理解背后的数学,但它会给你提供线索。
我同意你的看法,复合设计模式对于表达式的对象表示非常有用。以下示例来自我的代码,其目的是保存并打印表达式,但您可以轻松修改它以捕捉到这个想法。
表达式是根对象。它有后代,如CompoundExpression,Number,Variable等。
public interface Expression {
/**
* @return a numeric value of the expression
*/
double getValue();
/**
* @return a string representation of the expression
*/
String getExpression();
/**
* @return true if the expression is an atomic expression
*/
boolean isLeaf();
}
CompoundExpression 是操作的容器,作为其操作数。
public class CompoundExpression implements Expression {
/**
* Creates a compound expression.
* @param operation the specified operation
* @param operands The specified operands. The amount of operands must exactly
* match the arity of the operation.
*/
public CompoundExpression(Operation operation, Expression ... operands) {
super();
this.operands = Arrays.asList(operands);
this.operation = operation;
}
/**
* The expressions which this expression is compound of ;)
*/
final private List<Expression> operands;
/**
* The operation on operands.
*/
final private Operation operation;
/**
* {@inheritDoc}
*/
@Override
public String getExpression() {
return this.operation.compose(this.operands);
}
/**
* {@inheritDoc}
*/
@Override
public double getValue() {
return this.operation.calculate(this.operands);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
....
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
....
}
/**
* {@inheritDoc}
*/
@Override
public boolean isLeaf() {
return false;
}
}
数字是一片叶子。您可以实现更多类型的叶子,例如Variable。
public class Number implements Expression {
/**
* Creates an atomic expression with the specified value.
* @param value the numeric value
*/
public Number(double value) {
super();
this.value = value;
}
/**
* The numeric value of the number.
*/
private double value;
/**
* {@inheritDoc}
*/
@Override
public String getExpression() {
return String.valueOf(this.value);
}
/**
* {@inheritDoc}
*/
@Override
public double getValue() {
return this.value;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
....
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
....
}
/**
* {@inheritDoc}
*/
@Override
public boolean isLeaf() {
return true;
}
}
操作保存操作,例如Plus,Sinus,Floor,Ceiling,......如果需要,它还可以实际计算值。< / p>
public interface Operation {
/**
* Returns a numeric value of the operation performed on the given operands.
*
* @param operands the list of operands
* @return a numeric value of the operation
*/
double calculate(List<Expression> operands);
/**
* Returns a string representation of the operation performed on the given operands.
* @param operands operands the list of operands
* @return a string representation of the operation
*/
String compose(List<Expression> operands);
/**
* Returns a string representation of the operator
* @return string representation of the operator
*/
String getOperator();
}
BinaryOperation 是所有二进制操作的父级。它不一定需要,但它很方便。
public abstract class BinaryOperation implements Operation {
/**
* {@inheritDoc}
*/
@Override
public String compose(List<Expression> operands) {
assert (operands.size() == 2);
final Expression op1 = operands.get(0);
final Expression op2 = operands.get(1);
final boolean op1Leaf = op1.isLeaf();
final boolean op2Leaf = op2.isLeaf();
final StringBuilder builder = new StringBuilder();
if (!op1Leaf) {
builder.append("(");
}
builder.append(op1.getExpression());
if (!op1Leaf) {
builder.append(")");
}
builder.append(this.getOperator());
if (!op2Leaf) {
builder.append("(");
}
builder.append(op2.getExpression());
if (!op2Leaf) {
builder.append(")");
}
return builder.toString();
}
}
二元操作的一个例子:
public class PlusOperation extends BinaryOperation {
/**
* {@inheritDoc}
*/
@Override
public double calculate(List<Expression> operands) {
assert (operands.size() == 2);
return operands.get(0).getValue() + operands.get(1).getValue();
}
/**
* {@inheritDoc}
*/
@Override
public String getOperator() {
return "+";
}
}
UnaryOperation 是所有一元操作的父级。它不一定需要,但它很方便。
public abstract class UnaryOperation implements Operation {
/**
* {@inheritDoc}
*/
@Override
public String compose(List<Expression> operands) {
assert (operands.size() == 1);
return this.getOperator() + "(" + operands.get(0).getExpression() + ")";
}
}
一元操作的一个例子:
public class CosinusOperation extends UnaryOperation {
/**
* {@inheritDoc}
*/
@Override
public double calculate(List<Expression> operands) {
assert (operands.size() == 1);
return Math.cos(operands.get(0).getValue());
}
/**
* {@inheritDoc}
*/
@Override
public String getOperator() {
return "cos";
}
}
如何使用它。您可以“手动”创建如下表达式:
Expression exp = new CompoundExpression(
new PlusOperation(),
new CompoundExpression(
new DivisionOperation(),
new CompoundExpression(
new PlusOperation(),
new Number(2),
new Number(3)
),
new Number(4)
),
);
您必须使用下推自动机的实现来创建表达式:)