Solution to c2b8: Irresponsible rectangle
See code at solutions/code/tutorialquestions/questionc2b8
There is a clue in the title of this
question. The problem with the design of these classes is that class Rectangle
should be responsible for operations on rectangles, including calculating a rectangle's
area, checking containment between rectangles, and retrieving the bottom-right coordinates
of a rectangle. However, in the given classes, methods implementing these services form
part of the DrawingEngine
class. The Rectangle
class is irresponsible
because it lets anther class implement its functionality.
Notice that in DrawingEngine
's implementation of, e.g., area
, no reference
is made to any fields of DrawingEngine
. This is a little suspicious: a method usually
queries or updates data fields of the object on which is invoked. This "bad smell" is known as
feature envy: where a method seems more interested in a class other than the one it belongs
to. We can say here that DrawingEngine
envies Rectangle
: it has
stolen some of its features.
In the sample solution, you will see that the rectangle-centric methods of DrawingEngine
have all
been moved into the Rectangle
class. The clumsily named rectangleToString
method of DrawingEngine
has been removed, and instead the toString
method
has been implemented in Rectangle
, with the same behaviour. Notice that maxArea
stays where it is: this method computes the maximum area among all the rectangles stored in a
DrawingEngine
, so DrawingEngine
is the right place for this method. Notice further,
however, that the implementation of maxArea
has changed, so that it calls the area
method of Rectangle
, rather than the old area
method of DrawingEngine
.
Why is it a bad idea for DrawingEngine
to provide methods that should belong to Rectangle
?
Because we may very well wish to make use of rectangles in other contexts. For instance, a Page
class might use a Rectangle
to represent its drawing region. Suppose an instance method of
Page
requires the area of the page's drawing region. If the area
method belongs to DrawingEngine
,
then Page
will need to get a reference to a DrawingEngine
object and invoke area
on
this object, passing the drawing region rectangle of interest. This means that Page
is dependent on
DrawingEngine
, even though there may be no intuitive relationship between these classes. This bad
design can lead to an ugly application that is hard to understand and maintain.