|
Question
|
When would I use the delegation pattern instead of inheritence to extend a class's behavior?
|
|
Derived from
|
A question posed by John Zukowski PREMIUM
|
|
Topics
|
Process:Patterns
|
|
Author
|
John Moore PREMIUM
|
|
Created
|
Mar 23, 2000
|
Modified
|
Mar 23, 2000
|
|
Answer
Both delegation and inheritance are important
concepts in object-oriented software design,
but not everyone would label them as patterns.
In particular, the seminal book on design
patterns by the Gang of Four contains
a discussion of inheritance and delegation, but
the authors do not treat these topics as
specific patterns. It is reasonable to think
of them as design concepts which are more
general than specific design patterns.
Inheritance is a relationship between two classes
where one class, called a subclass in this
context, inherits the attributes and operations
of another class, called its superclass.
Inheritance can be a powerful design/reuse
technique, especially when it is used in the
context of the Liskov Substitution Principle.
(The article by Robert Martin at
http://www.objectmentor.com/publications/lsp.pdf
provides an excellent explanation of the ideas
behind Barbara Liskovs original paper on
using inheritance correctly.) The primary
advantages of inheritance are
- it is directly supported by object-oriented
languages, and
- it provides the context for polymorphism in
strongly-typed object-oriented languages
such as C++ and Java.
But since the inheritance relationship is defined
at compile-time, a class cant change its
superclass dynamically during program execution.
Moreover, modifications to a superclass
automatically propagate to the subclass,
providing a two-edged sword for software
maintenance and reuse. In summary, inheritance
creates a strong, static coupling between a
superclass and its subclasses.
Delegation can be viewed as a relationship
between objects where one object forwards certain
method calls to another object, called its
delegate. Delegation can also a powerful
design/reuse technique. The primary advantage
of delegation is run-time flexibility
the delegate can easily be changed at run-time.
But unlike inheritance, delegation is not
directly supported by most popular
object-oriented languages, and it doesnt
facilitate dynamic polymorphism.
As a simple example, consider the relationship
between a Rectangle class and a Window class.
With inheritance, a Window class would inherit
its rectangular properties from class
Rectangle. With delegation, a Window object
would maintain a reference or pointer to a
Rectangle object, and calls to rectangle-like
methods of the Window object would be delegated
to corresponding methods of the Rectangle object.
Now lets consider a slightly more complex
example. Suppose employees can classified based
on how they are paid; e.g., hourly or salaried.
Using inheritance, we might design three classes:
an Employee class which encapsulates the
functionality common to all employees, and two
subclasses HourlyEmployee and SalariedEmployee
which encapsulates pay-specific details. While
this design might be suitable for some
applications, we would encounter
problems in a scenario where a person changes,
say from hourly to salaried. The class of an
object and the inheritance relationship are both
static, and objects cant change their
class easily (but see the State pattern for
tips on how to fake it).
A more flexible design would involve delegation
an Employee object could delegate
pay-related method calls to an object whose
responsibilities focused solely on how the
employee is paid. In fact, we might still use
inheritance here in a slightly different manner
by creating an abstract class (or interface)
called PayClassification with two subclasses
HourlyPayClassification and
SalariedPayClassification which implement
classification-specific computations. Using
delegation as shown, it would be much easier
to change the pay classification of an
existing Employee object.
This second example illustrates an important
point: In implementing delegation, we often
want the capability to replace the delegate with
another object, possibly of a different class.
Therefore delegation will often use inheritance
and polymorphism, with classes of potential
delegates being subclasses of an abstract
class which encapsulates general delegate
responsibilities.
One final point. Sometimes, the choice between
delegation and inheritance is driven by external
factors such as programming language support
for multiple inheritance or design constraints
requiring polymorphism. Consider threads in
Java. You can associate a class with a thread
in one of two ways: either by extending
(inheriting) directly from class Thread, or by
implementing the Runnable interface and then
delegating to a Thread object. Often the
approach taken is based on the restriction
in Java that a class can only extend one class
(i.e., Java does not support multiple
inheritance). If the class you want to
associate with a thread already extends some
other class in the design, then you would have
to use delegation; otherwise, extending class
Thread would usually be the simpler approach.
Is this item
helpful? yes no
Previous votes Yes: 8 No: 0
|
|
Comments and alternative answers
 |
When you don't have static relationship between the
...
Madhusudan Chaganthi, Mar 23, 2000 [replies:1]
When you don't have static relationship between the
parent class and the child class.
For example, role management using Person class
should be using delegation instead of making a
sub-class for every kind of role that a Person
can fill.
To do this, the 2nd class uses an instance of the
parent class to delegate to take care of the original
functionality.
Class Person{
// person specific implementation
.....
}// end of Person
Class SomeRole{
private Person person;
// SomeRole specific implementation
.........
// Person specific delegation
... PersonMethod1(){
return person.PersonMethod1();
}
} // end of SomeRole
Class Client{
SomeRole someRole = new SomeRole();
// call role specific methods
someRole.roleMethod1();
.........
// call Person specific methods
someRole.PersonMethod1();
..........
} // end of Client
Is this item
helpful? yes no
Previous votes Yes: 1 No: 0
|
|

|
 |
When the new class IS NOT a type of the old class....
Sriram Gopalan, Mar 23, 2000
When the new class IS NOT a type of the old class. What I mean is, inheritance is typically used only for modelling strict IS-A relationships rather than for reusing existing code.
For example, if you are designing a GUI system, you may be tempted to inherit "Window" from "rectangle" to make programming easier. But, you have to keep in mind that a window "has a rectangular shape", but a window "IS NOT a rectangle". So, the better alternative would be to have the methods related to the shape (calculating bounds, for example) delegated to the rectangle (shape) object, rather than inheriting from it.
If tomorrow (for some reason :) ), your GUI has to be redone with circular windows, this will still work - only the shape member variable will point to the circle object now. Compare with if you had inherited from rectangle!
Is this item
helpful? yes no
Previous votes Yes: 0 No: 0
|
|

|
|
|
 |
|