## Point and ColorPoint

This lesson is based on the book "Effective Java, Programming Language Guide". It concerns versions 1 to 4.

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(Object)`. 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 possible to have a "`Point` view" of an instance of `ColorPoint`. In that 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)`. `ColorPoint` is also adapted in the same way.
We create a new subclass of `Point`, `BoundedPoint`, which manage points with bounded coordinates. If the user wants to move a bounded point outside its bounds, the point remains at its previous coordinates. An `IllegalArgumentException` (subclass of the class `RuntimeException`) is thrown in the constructor if the bounds do not contain the initial coordinates. Note that the variable `rectangle` in `BoundedPoint` contains a copy of the rectangle given as parameter in the constructor, to avoid modifications of the bounds by modifying the rectangle given as parameter outside of the class `BoundedPoint`.
The `Test` class shows that the coordinates of a bounded point are correctly checked when using the method ```moveTo(int, int)``` on an instance of `BoundedPoint`. But, if we use the method `moveTo(int, int)` on the `Point` view, the instance of `BoundedPoint` may be moved outside its bounds.
The result of the command

`> java Test`

is ``` Current point = (5,5) Bounds : java.awt.Rectangle[x=0,y=0,width=10,height=10] Current point = (20,20) Bounds : java.awt.Rectangle[x=0,y=0,width=10,height=10]```

#### Version 6

To have a better control in `BoundedPoint` on the delegation to the instance of `Point`, we no longer use a direct instance of `Point`, but an instance of an internal subclass, called `InternalClass`.
The class `Test` allows to see that now, all the moves of a bounded point, even using its view as point, are properly managed.
The result of the command

`> java Test`

is

```Current point = (5,5) Bounds : java.awt.Rectangle[x=0,y=0,width=10,height=10] Current point = (5,5) Bounds : java.awt.Rectangle[x=0,y=0,width=10,height=10] ```

#### Version 7

Now, suppose that we want to replace the beahvior of an instance of `BoundedPoint` : if the new coordinates are out of bounds, we prefer to throw an exception than leaving the point unchanged. But because `BoundedPoint` inherits from `Point`, that means that the method `move(int, int)` in `Point` must declare this exception. Thus, we define a class `IllegalMoveException`, and this exception may be thrown by any kind of instance of `Point`, `ColorPoint` or `BoundedPoint`.
The best way to obtain the expected result is to create a new interface `Point`, to rename the former class `Point` by `PointImpl`, and to adapt the classes `PointImpl`, `ColorPoint` and `BoundedPoint` in such a way that they implement the interface `Point`. Note that in that case, the view returned by `asPoint()` is no more necessary as all the instances of both `PointImpl`, `ColorPoint` and `BoundedPoint` are also instances of `Point`, as shown by the class `Test`.
The result of the command

`> java Test`

is

```Point (5,5) Bounds : java.awt.Rectangle[x=0,y=0,width=10,height=10] cannot go to (20,20) ```