Favour containment over association
Line 24: | Line 24: | ||
− | + | ==Conflicts== | |
+ | * [[A class should not depend on its users]] | ||
== See also == | == See also == | ||
* [[Riel's heuristics]] | * [[Riel's heuristics]] |
Revision as of 05:22, 6 October 2008
Reil's heuristic #7.1
The containment relationship should be favoured over the association relationship when there is a question about where to hold a class that is required by another class. For example consider a fighter jet that has a PlaneWing which carries Missiles. Each Missile uses a Launcher to fire it, and the launching of Missiles is controlled by a LaunchRegulator. Once a missile locks onto a target it alerts the LaunchRegulator that it is ready to fire. The problem is to decide what relationship is best between Missiles and Launchers. Should each Missile hold a Launcher (the containment relationship) or should a PlaneWing have an array of Launchers that are each associated with a Missile? The two potential solutions are shown below:
Association solution:
This solution seems to be the most efficient and straightforward. When a Missile acquires a target, it alerts the LaunchRegulator which tells the PlaneWing to unlock the Missile and fire the associated Launcher. However in order to know which Launcher to fire, the PlaneWing needs to know which Missile initiated the call and find the associated Launcher. This can be done by passing the name of the Missile and having the PlaneWing search through the Launchers until it finds a match. It may seem obvious that since the PlaneWing knows when the Launcher can be fired, the PlaneWing should tell the Launcher to fire. However this implies that the PlaneWing contains the Launchers. An alternate solution is shown below:
Containment solution:
This solution has a lot more communication between classes. When a Missile acquires a target, it alerts the LaunchRegulator, which tells the PlaneWing to unlock the Missile. The PlaneWing then tells the LaunchRegulator that it is ready, so the LaunchRegulator tells the Missile to fire it's Launcher. If we follow the heuristic we should go with this design, however the first design seems to be much cleaner and more straightforward.
The reason we should favour containment over association, even if it looks messier on paper, is to ensure that we don't add conventions into the design for creating classes. Consider the association solution: when a user wishes to create a new Missile object, they must also know to create a new Launcher object for the PlaneWing class. This makes the Missile class aware of and dependent on the implementation of the PlaneWing class. In the containment solution, if a user wishes to create a new Missile object the Launcher for it is created implicitly because every Missile must contain a Launcher. This means that the implementation details of the Missile class are hidden from the user.