I am building out a binary expression tree and shown below is an implementation of the tree's node.
The node can be either a leaf or non-leaf, with leaves having Integer
type values and non-leaves having ExpressionTreeNodeOperands
type values. Leaves may have neither left nor right child nodes, and non-leaves must have both left and right child nodes.
I feel like this could be solved more appropriately using inheritance but can't seem to wrap my head around the generic Object
member.
public class ExpressionTreeNode {
private Object value;
private ExpressionTreeNode leftNode;
private ExpressionTreeNode rightNode;
public ExpressionTreeNode(Object value) {
this(value, null, null);
}
public ExpressionTreeNode(Object value, ExpressionTreeNode leftNode, ExpressionTreeNode rightNode) {
if (value == null || (!(value instanceof Integer) && !(value instanceof ExpressionTreeNodeOperands))) {
throw new IllegalArgumentException("Illegal argument: value must be non-null with a type of Integer or ExpressionTreeNodeOperand");
}
if (leftNode == null && rightNode != null || leftNode != null && rightNode == null) {
throw new IllegalStateException("Illegal state: leftNode and rightNode should both be null or non-null alike");
}
if ((value instanceof Integer) && (leftNode != null && rightNode != null)) {
throw new IllegalStateException("Illegal state: non-operand non-leaf node");
}
if (!(value instanceof Integer) && leftNode == null && rightNode == null) {
throw new IllegalStateException("Illegal state: non-integer leaf node");
}
this.value = value;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
public boolean isLeafNode() {
return (leftNode == null) && (rightNode == null);
}
public Object getValue() {
return value;
}
public ExpressionTreeNode getLeftNode() {
return leftNode;
}
public ExpressionTreeNode getRightNode() {
return rightNode;
}
}