What is it?
Chances are if you have used AWT1.1 or Swing, you have already used the
delegation pattern, you just didn’t know you were doing it. The delegation
pattern can be defined as follows. When you are creating a class that does
everything another class does and more, then instead of subclassing the other
class, you have to declare it as a data member or property of your class.
Example Problem
Lets say you are writing a class (ClassA) that does what another class
(ClassB) does. ClassA also has to do more things (have more methods) than what
ClassB does. You might be tempted to simply have ClassA subclass ClassB.
Resist this temptation, becuase it is the
wrong thing to do. Inheritance is inherently slow, and is a very strong linkage
in your design. As a rule you want to create loosely coupled, but strongly
coherent systems.
Solution (design)
The correct design involves defining a data member of type ClassB in ClassA.
This way, you have eliminated the need for subclassing and reduced the coupling
strength. In fact, ClassB might just be an interface, which is even better for
loose coupling.
Code
1: //ClassA
2: public class ClassA{
3: //data
4: private ClassB classB;
5:
6: //methods
7: public void doThis(){classB.doThis();}
8: public void doThat(){…}
9: }
1: //ClassB
2: public class ClassB{
3: public void doThis(){…}
4: }
Why?
The delegation pattern allows your code to be loosely coupled, which is a
very important goal of any object oriented system. It is easy to get this
pattern confused with the adapter pattern, they are similar, but completely
different. Study both patterns carefully and you will see how they are totally
different (yet similar).
Delegation pattern
In
software
engineering, the
delegation pattern is a
design pattern in
object-oriented programming where
an
object, instead of performing one of
its stated tasks, delegates that task to an associated helper object. There is
an
Inversion of Responsibility in
which a helper object, known as a
delegate, is given the responsibility
to execute a task for the
delegator. The delegation pattern is one of the
fundamental
abstraction patterns that
underlie other software patterns such as
composition (also referred to as
aggregation),
mixins and
aspects.
Examples
[edit]
Java examples
[edit]
Simple
In this
Java example, the
Printer class
has a
print method. This print
method, rather than performing the print itself, delegates to class
RealPrinter. To the outside world it
appears that the
Printer class is
doing the print, but the
RealPrinter class is the one actually
doing the work.
Delegation is simply passing a duty off to someone/something else. Here is a
simple example:
class RealPrinter { // the "delegate"
void print() {
System.out.println("something");
}
}
class Printer { // the "delegator"
RealPrinter p = new RealPrinter(); // create the delegate
void print() {
p.print(); // delegation
}
}
public class Main {
// to the outside world it looks like Printer actually prints.
public static void main(String[] args) {
Printer printer = new Printer();
printer.print();
}
}
[edit]
Complex
By using
interfaces, delegation can be made more
flexible and
typesafe. "Flexibility" here means that
C need not refer to
A or
B in any way, as the switching of
delegation is abstracted from
C.
Needless to say,
toA and
toB don't count as references to
A and
B. In this example, class
C can delegate to either class
A or class
B. Class
C has methods to switch between classes
A and
B. Including the
implements
clauses improves
type
safety, because each class must implement the methods in the interface. The
main tradeoff is more code.
interface I {
void f();
void g();
}
class A implements I {
public void f() { System.out.println("A: doing f()"); }
public void g() { System.out.println("A: doing g()"); }
}
class B implements I {
public void f() { System.out.println("B: doing f()"); }
public void g() { System.out.println("B: doing g()"); }
}
class C implements I {
// delegation
I i = new A();
public void f() { i.f(); }
public void g() { i.g(); }
// normal attributes
public void toA() { i = new A(); }
public void toB() { i = new B(); }
}
public class Main {
public static void main(String[] args) {
C c = new C();
c.f(); // output: A: doing f()
c.g(); // output: A: doing g()
c.toB();
c.f(); // output: B: doing f()
c.g(); // output: B: doing g()
}
}