Effective Java by Joshua Blotch states:
There is no way to extend an instantiable class and add a value component while preserving the
equals
contract, unless you are willing to forgo the benefits of object-oriented abstraction.
Effective Java gives some examples which either break symmetry, transitivity or Liskov substitution principle. I suppose you have read the item. I don't think I should post the whole item here. However I found a solution which obeys the contract:
The Point
:
public class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
protected boolean equalsImpl(Point p){
return p.x == x && p.y == y;
}
@Override
public final boolean equals(Object o) {
if(!(o instanceof Point))
return false;
Point p = (Point)o;
return equalsImpl(p) && p.equalsImpl(this);
}
// Remainder omitted ...
}
The ColorPoint
:
public class ColorPoint extends Point{
private java.awt.Color color;
public ColorPoint(int x, int y, java.awt.Color color){
super(x, y);
this.color = color;
}
@Override
protected boolean equalsImpl(Point p){
return (p instanceof ColorPoint) &&
super.equalsImpl(p) &&
((ColorPoint)p).color == color;
}
// Remainder omitted ...
}
I know composition should be used in this case, but I wonder whether my solution really obeys the equals
contract. If yes, is what Effective Java states wrong?