You're working with what we might call an Abstract Syntax Tree.
The purpose of the tree is to capture an expression. There are other ways to capture expressions, such as text. A text form is a serialization. In some serializations of expressions (e.g. infix), we need to use parenthesis — ()'s — to override operator precedence; however, in an AST, the operator precedence is explicit in the shape of the tree, so no parenthesis are necessary.
We capture expressions as trees for a variety of reasons. In compiler technology, expressions are often represented as trees at some point in the translation process (e.g. parse output). The compiler's task is to translate the expression into a form (usually lower level, like byte-code or machine code) for later execution (or further translation for later execution).
Such a tree might also be evaluated instead of translated; this might occur, for example, in an interpreter. In an interpreter, usually evaluation of such an expression tree would happen after the construction of the tree; this is because the interpreter may choose to analyze the expression (tree) before evaluation, and/or, because the interpreter wants to be able to evaluate the expression more than once — each time with possibly different values for variables, so the same expression can yield a different final result if variables are updated.
In your case as there are no variables (only constants), there is no (obvious) advantage to delaying execution — so you might be tempted to consider doing execution as part of construction. This would imply having a result or value for all entities before construction, and so you might provide, in the abstract base class, a constructor that receives the value, and a field that holds the value; however, as you note, that would require that the
AdditionExpression also construct in terms of values, and this would be a different assignment.
By the text of your requirements, (1) you must provide a
calculate() method for (post-construction) evaluation of the expression, and (2) you must provide a constructor for
AdditionExpression that takes two
Expressions and no values!!
Your job is to support tree construction for later evaluation, not to build a tree while simultaneously computing its final value. So, separate those concepts in your mind — construction of the tree from evaluation of the tree. Evaluation will be done post construction.
If I were to forgo a constructor in Expression then I can't really override equals in Expression because I need to be able to make comparison based on some field.
To repeat myself, you are conflating construction with evaluation. In the model of those requirements, construction happens first, and evaluation is delayed until construction is completed.
The override for
equals(...) will execute only in the post-construction environment. No one will call
equals during construction of the tree, eh?
Thus, in your
equals override you can assume that trees are fully constructed! Fully constructed trees support the interface provided by the abstract class
Expression — they can be evaluated to obtain their value!