Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
The delegation pattern simplifies a number of thorny inheritance and domain design problems. When incorporating the delegation pattern in your application, consider these principles:
Use the delegation pattern when the behavior of an object should be open to customization and the nature or knowledge needed to implement that customization is outside the domain of the class. In the AutomaticPerimeterDefenseGun example, the class encapsulates a weapon that shoots at targets, but deciding on which targets are friendly is outside its domain.
Delegates are particularly effective when implemented in the base class with multiple subclasses. Each subclass can consistently employ the delegate without complicating the number or organization of subclasses.
An object should have a well-defined behavior in the absence of a delegate object (delegate==nil). In the -defendPerimeter method, the delegate is unconditionally sent the -gun:shouldShootAt: message. If the delegate is nil, the message returns nil, and the gun shoots at nothing—a desirable trait in the absence of any targeting information. See the "absent behavior" and "consistency with nothing" design patterns in Chapter 7.
Similarly, an object should provide some natural baseline functionality when optional delegate methods are absent. The -acquireTargets method in Listing 17-2 tests the delegate to see if it responds to -gun:prioritizeTargets:. If it does, it passes the known target list to the delegate that will prioritize, filter, or possibly supply its own targets. If the delegate doesn't implement the method, the gun uses the targets it obtained from its sensors. Note that this is also consistent with the previous principle, as -responsesToSelector: will return NO if the delegate is nil.
An object should always provide context in the delegate message. The delegate methods in Listing 17-2 all include the Gun object that's sending the message to the receiver. This allows the delegate to include the sender in its decision process, like telling the gun to stop firing if its ammunition gets too low. Remember that a single delegate object might be set as the delegate for two, or a hundred, different objects. Some delegates act as reusable traits, like the validation routine in Listing 17-1, that can be shared by arbitrary groups of similar objects.