Skip to content

Latest commit

 

History

History
38 lines (32 loc) · 2.55 KB

c2b8.md

File metadata and controls

38 lines (32 loc) · 2.55 KB

Back to questions

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.