2014-01-14 126 views
1

我正在構建一個用於符號計算的java庫。 我製作了一個抽象表達式類,用於在產品,分數和多項式之間進行各種操作。但是,當我想增加樓層和天花板時,情況變得複雜。我知道我周圍有這樣的圖書館,我想知道是否有一個特定的設計模式要遵循,或者是否有任何資源可以尋找靈感和指導。符號庫設計模式

+0

哼哼的實現,以創建表達,你到底要求什麼呢? –

+0

隨着我向符號庫添加越來越多的功能,我面臨嚴重的設計問題。一開始我只使用符號產品,例如'a * b',那麼我就有一部分產品是另一種產品。當我想要多項式表達式時,事情就會變得棘手,因爲我無法用多項式來輕鬆定義除法。事情變得越來越複雜,我開始遵循或多或少的複合設計模式。不過,我覺得重新發明輪子,如果有人知道在哪裏可以找到更多信息,這將非常有幫助。 –

回答

2

很可能你正在做的是解析一個「上下文無關語言」(Type-2,根據Chomsky hierarchy)。嘗試閱讀http://en.wikipedia.org/wiki/LL_parserhttp://en.wikipedia.org/wiki/Pushdown_automaton - 你不一定要了解背後的數學,但它會給你提供線索。

我同意你的觀點,複合設計模式對錶達式的對象表示非常有用。下面的例子來自我的代碼,它的目的是保持一個表達式,但你可以很容易地修改它來捕捉這個想法。

表達式是根對象。它有後代如CompoundExpression,數字,可變等等

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; 
    } 
} 

是葉。你可以實現更多類型的葉子,比如變量。

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; 
    } 
} 

操作保持操作,如加,竇,地板,天花板,......它也可能有必要時實際計算價值的能力。

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) 
    ), 
); 

而且你必須使用一個下推自動機:)

+0

感謝您的時間和回答Honza。我會看看所有這些,並提供反饋意見。 –

+0

它看起來像我可以使用的東西。但是,我認爲我沒有時間去完成這個計劃的過渡,但我會保留它作爲未來的參考。 –