Square and Rectangle
We consider the following class Rectangle
.
We want to add a new class Square
, and to avoid
duplication, we want to re-use the class Rectangle
.
Version 1
In mathematics, every square is a rectangle and it is quite a natural
idea to apply this assertion to the classes Square
and Rectangle
:
In terms of object programming, this assertion may be translated into
"Square
extends Rectangle
". Thus,
we propose the following implementation of the class Square
.
But this idea is wrong !
To prove it, we consider,
for example in a class Rectangles
,
the following static method
public static void resize(Rectangle r, int factor) {
r.setHeight(factor * r.height());
r.setWidth(factor * r.width());
}
and, for example in a class Test
, the following main
method :
public static void main(String[] args) {
Rectangle r = new Rectangle(10, 10);
Square s = new Square(10);
Rectangles.resize(r, 2);
System.out.println("height = " + r.height() + "
width = "
+
r.width());
Rectangles.resize(s, 2);
System.out.println("height = " + s.height() + "
width = "
+
s.width());
}
The result of the command
> java Test
is the following :
height = 20 width = 20
height = 40 width = 40
while we were expecting
height = 20 width = 20
height = 20 width = 20
The reason is that the size (i.e. both height and width) of the
square s
is modified twice, once when calling setHeight
,
once when calling setWith
in resize.
Version 2
In this version, we use inheritance again, but in such a
way that there will be no direct relationship between Rectangle
and Square
.
To factorize code between Rectangle
and Square
,
we use an abstract class : AbstractRectangle
, but in such
a way that this class cannot be used by the "client" of Rectangle
and Square
. For that, we introduce a package rectangle
which will contain the three classes Rectangle
,
Square
, AbstractRectangle
.
The Test
class remains in the default package.
Note that the abstract class written to factorize the code could be public
if you think that it may be reused by the client to write a new
subclass. If not, it is better to limit its visibility to its
package.
Version 3
This version is the best, because it is simpler than the previous one.
It
is based on delegation.
Concretely, it means that each instance of Square
uses an instance of Rectangle
to "do the job". This
instance is called delegate
in the implementation. The
classes Rectangle
and Test
remain
unchanged from the version 2.