I'm sure you'll get some definitions, but here are some examples that m=
ay
help...
One place where delegation is used is when you want to push extensibili=
ty
'downward' instead of
'upward'. Upward extensibility is provided by way of derivation. I prov=
ide a
generic base class and you
derive from it to create a different class. All code written to this in=
terface
deals through the base class
(or interface) polymorphically.
But, in some cases, you want to have a single class be the public perso=
na for
something and force
the extensibility 'downwards'. In this case, the public class is a conc=
rete
class, but its only member is
a reference to an 'implementation object' which may or may not be polym=
orphic.
The public class'
implementation is nothing but a set of methods which turn around and ca=
ll a
sibling method in the
implementation class. Sometimes they do a little value added work, or d=
o
pre/post condition
checking and so forth. So the public class just delegates all the work =
to some
actual implementation
class.
The benefit of this is more conceptual than technical I guess. I use it=
in my
CIDLib class libraries. There
is a 'kernel abstraction' DLL which encapsulates all system and RTL acc=
ess. The
classes in there are
very simple and are not for public viewing. The next level up creates p=
ublic
classes, each of which just
uses its sibling class in the kernel, delegating all work to it, but
translating all errors propogating out into
more complex, publically useful errors.
In this case, the implementation classes are not used polymorphically. =
Since
one version of each kernel
implementation class exists per operating system platform supported, th=
ey each
implement the exact
same class name are just used monomorphically (since they will never ex=
ist at
the same time.) This
speeds things up, particuarly since the public class' methods are often=
just
inlines that delegate to the
underlying kernel class. It also makes life simpler for the public who =
can deal
with concrete classes,
it allows a very clean separation between platform dependent and indepe=
ndent
code, and does not
tie the public API to the internal API via inheritance.
The other scenario is the 'how to aggregate' type of thing. The classic=
scenario is a tricycle. If I build
a tricycle from a seat class, a front wheel class, a frame class, and a=
handle
bar class, how do I
aggregate that? Some folks would say you have base interfaces for such =
things
(or mixins in C++) and
mix them into a single Trycycle class. This gets maximum reuse for mini=
mum
effort, and it directly
models the system being built, which is aggregated in the same way.
However, its not really that clean. A 'thing' once put into a coherent =
system,
often does not exhibit the
same 'degrees of freedom' that it had as a standlone unit. For instance=
, if you
mixed in the interfaces
for all of these objects, then all of the freedom of the standalone thi=
ngs will
'show through'. In other
words, you could call the wheel's 'Turn()' method directly. But in a re=
al
aggregate system, everything
has new constraints which are defined by the system, not by the bits. Y=
ou
cannot turn a tricycle's
whell without also turning the handlebars (at least if its working righ=
t.)
Aggregation via delegation deals with this issue while still allowing f=
or
reuse. The Tricycle class
just 'Has-A' wheel, seat, frame, and handlebar object. It then exposes =
a new
API which expresses
the constraints of the system. This new API then just turns around and
delegates the actions to the
individual bits, but it enforces the constraints. It provides a 'Turn()=
' which
insures that the handle bar
and wheel objects are turned together, by just passing on the event to =
them
both and insuring that
they never turn separately (unless it supports a "Crash()" API perhaps =
:-)
This is not to say that mixing in functionality via mixin classes or in=
terfaces
is not useful. Its just that
its more useful when modelling 'optional behavior' type of stuff. Model=
ling
real world aggregation
is more often better served by aggregation and delegation, though it do=
es
require more work and
some more code bloat to do it.
Anyway, that's a quickie explanation of where it can be useful and why.=
There
are others but I'm sure
no one wants us writing small books on off topic stuff here.
----------------------------------------
Dean Roddey
Software Weenie
IBM Center for Java Technology - Silicon Valley
roddey@us.ibm.com
=