|< Free Open Study >|
4.9 More Containment Heuristics
This heuristic is important if a designer wishes to reuse his or her abstractions. Consider the relationship "BedRoom contains AlarmClock". It is necessary that the BedRoom object knows about its contained AlarmClock object, but the AlarmClock should have no dependencies on the BedRoom. The main reason is reusability. I want to be able to take the AlarmClock out of the BedRoom and use it in the design of a TimeLockSafe. If the AlarmClock is dependent on the BedRoom, then the BedRoom goes wherever the AlarmClock goes. This implies that the Bed, SleepingHuman, NightStand, Bureau, Trunk, etc. also go where the AlarmClock goes since they are contained together in the BedRoom. Objects of the TimeLockSafe class are now dependent on NightStands, Beds, Trunks, etc.
Objects that share lexical scope are objects that are contained in the same containing class. The reason they should not be using each other is anchored in both reusability and complexity issues. Consider Figure 4.12's fragment of an automatic teller machine design, which focuses on an ATM attempting to get a pin number from its user. The card reader has detected that it has a legal bank card. The system now needs to get a pin number for verification. A typical solution is for the card reader to ask the ATM's display screen to display a prompt to the user, followed by the card reader asking the keypad to get a pin number.
The problem in this design is initially a reusability issue. Card readers have nothing to do with display screens and keypads outside of the domain of automatic teller machines. If I want to reuse the card reader in a security door, I have to place a display screen and keypad in the door because card readers are dependent on them. This clearly hinders the reuse of the class sending the messages.
Even if a developer decides that he or she does not care about reusability, there is a serious complexity issue that needs resolution. The automatic teller machine contains all three objects, which implies that there are uses relationships between the ATM and card reader, the ATM and display screen, and the ATM and keypad. The ATM can handle any coordinated activity between these three classes. By adding a uses relationship between the card reader and display screen, we are adding complexity to the design whose functionality is already available in the ATM machine. A better solution is to allow the ATM to find that it has a card, prompt the user via its display screen, and get a pin number from its keypad (see Figure 4.13). In general, the containing class should use its existing uses relationships to accomplish the behavior that the lexical scope sharing objects are duplicating.
There is a notable area of design where a designer will violate Heuristic 4.13. This occurs when a number of different classes are dependent on one another in complex ways. Rather than have all of these complex dependencies, the designer wraps the related classes in a containing class. Each contained object sends messages to the containing class, which then broadcasts the message to the rest of the contained objects or a preselected list, depending on how the designer wants to distribute the system intelligence between the containing class and its contained pieces. In all of these designs, the designer is violating the heuristic in order to satisfy Heuristics 4.1 and 4.14. In short, having a contained object that knows about its container is preferable to a large number of uses relationships. Three case studies illustrate this violation of Heuristic 4.13:
|< Free Open Study >|