What about a hierarchy of algebraic expressions. It is an excellent example because it uses both inheritance and composition:
public interface Expression {
int evaluate();
public class Constant implements Expression {
private final int value;
public Constant(int value) {
this.value = value;
}
@Override
public int evaluate() {
return this.value;
}
@Override
public String toString() {
return String.format(" %d ", this.value);
}
}
public class Negate implements Expression {
private final Expression expression;
public Negate(Expression expression) {
this.expression = expression;
}
@Override
public int evaluate() {
return -(this.expression.evaluate());
}
@Override
public String toString() {
return String.format(" -%s ", this.expression);
}
}
public class Exponent implements Expression {
private final Expression expression;
private final int exponent;
public Exponent(Expression expression, int exponent) {
this.expression = expression;
this.exponent = exponent;
}
@Override
public int evaluate() {
return (int) Math.pow(this.expression.evaluate(), this.exponent);
}
@Override
public String toString() {
return String.format(" %s ^ %d", this.expression, this.exponent);
}
}
public class Addition implements Expression {
private final Expression left;
private final Expression right;
public Addition(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int evaluate() {
return this.left.evaluate() + this.right.evaluate();
}
@Override
public String toString() {
return String.format(" (%s + %s) ", this.left, this.right);
}
}
public class Multiplication implements Expression {
private final Expression left;
private final Expression right;
public Multiplication(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int evaluate() {
return this.left.evaluate() * this.right.evaluate();
}
@Override
public String toString() {
return String.format(" (%s * %s) ", this.left, this.right);
}
}
}
Then you can provide a motivating example like:
public static void main(String[] args) {
Expression two = new Constant(2);
Expression four = new Constant(4);
Expression negOne = new Negate(new Constant(1));
Expression sumTwoFour = new Addition(two, four);
Expression mult = new Multiplication(sumTwoFour, negOne);
Expression exp = new Exponent(mult, 2);
Expression res = new Addition(exp, new Constant(1));
System.out.println(res + " = " + res.evaluate());
}
Which would yield:
( ( ( 2 + 4 ) * - 1 ) ^ 2 + 1 ) = 37