Point and ColorPoint

This lesson is based on the book "Effective Java, Programming Language Guide".

We consider the following class Point.
We want to add a new class ColorPoint, which makes it possible to create points with a color property.

Version 1

In this version, ColorPoint does not override the method equals(Object). In that case, it means that two points with different colors are nevertheless equals if they have the same coordinates.  This is probably not what you want !

Version 2

In this version, ColorPoint overrides equals. Now, two color points are equals iff they have the same coordinates and the same colors.
Unfortunatly, this solution is wrong !

The equals(Object) method must respect the following mathematical properties  :
  1. reflexivity
    o1.equals(o1) is always true.
  2. symmetry
    o1.equals(o2) iff o2.equals(o1).
  3. transitivity
    if o1.equals(o2) and o2.equals(o3) are true, then o1.equals(o3) must be true.
But it is not the case with this implementation, as shown by the main method of the class Test :

public static void main(String[] args) {
    Point p = new Point(10, 10);
    ColorPoint cp = new ColorPoint(10, 10, Color.RED);
    System.out.println(cp.equals(p));
    System.out.println(p.equals(cp));
}


The result of the command

> java Test

is

false
true

Thus, the symmetry is not respected.

Version 3

In this version, we just modify the equals(Object) method of ColorPoint. If we compare a ColorPoint and a Point which is not an instance of ColorPoint, we don't take color into account. But this solution also is wrong, as shown by the new main method of the class Test :

public static void main(String[] args) {
    Point p = new Point(10, 10);
    ColorPoint cp1 = new ColorPoint(10,10,Color.BLUE);
    ColorPoint cp2 = new ColorPoint(10, 10, Color.RED);
    System.out.println(cp1.equals(p));
    System.out.println(p.equals(cp2));
    System.out.println(cp1.equals(cp2));       
}

The result of the command

> java Test

is

true
true
false

Thus the transitivity is not respected.

Version 4

The previous versions have proved that an instance of ColorPoint cannot be a Point except if we accept that two instances of ColorPoint may be equals with different colors. Thus we propose a new version of ColorPoint where we don't use inheritance, but only delegation. Note the method asPoint() which makes it possible to have a "Point view" of an instance of ColorPoint. In this case, it is very easy to implement such a view because an instance of Point is unmodifiable.

Version 5

We modify Point in such a way that now,  an instance of Point may be modified, using the new method moveTo(int x, int y). We modify ColorPoint in the same way. We also add a private method showMove() to ColorPoint which prints a message when an instance of ColorPoint is moved.
The Test class shows that this method is called when using the method moveTo(int, int) on an instance of ColorPoint. But, if we use the method moveTo(int, int) on the Point view, the instance of ColorPoint is moved, but the message is not printed.

The result of the command

> java Test

is

moving to (20,20)
Current  cp = (30,30) Color : java.awt.Color[r=0,g=0,b=255]

Version 6

To have a better control in ColorPoint on the delegation to the instance of Point, we no longer use a direct instance of Point, but an instance of a subclass, called InternalClass. To access the private method of ColoredPoint showMove(), this subclass must be an internal class of ColoredPoint.
The class Point remains unchanged, and the class Test allows to see that now, all the moves are printed.

The result of the command

> java Test

is

moving to (20,20)
moving to (30,30)