[
Lists Home |
Date Index |
Thread Index
]
- From: Dean Roddey <roddey@us.ibm.com>
- To: <xml-dev@ic.ac.uk>
- Date: Mon, 12 Oct 1998 14:43:39 -0400
>From: Peter Murray-Rust <peter@ursus.demon.co.uk>
>Date: Sun, 11 Oct 1998 21:03:56
>Subject: Re: Do we need link-catalogs for schemas?
>
>Question in return, what exactly is delegation and can you give an example.
>[It's been mentioned both in the context of Java classes and link-catalogs].
>
I'm sure you'll get some definitions, but here are some examples that may
help...
One place where delegation is used is when you want to push extensibility
'downward' instead of
'upward'. Upward extensibility is provided by way of derivation. I provide a
generic base class and you
derive from it to create a different class. All code written to this interface
deals through the base class
(or interface) polymorphically.
But, in some cases, you want to have a single class be the public persona for
something and force
the extensibility 'downwards'. In this case, the public class is a concrete
class, but its only member is
a reference to an 'implementation object' which may or may not be polymorphic.
The public class'
implementation is nothing but a set of methods which turn around and call a
sibling method in the
implementation class. Sometimes they do a little value added work, or do
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 access. The
classes in there are
very simple and are not for public viewing. The next level up creates public
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, they each
implement the exact
same class name are just used monomorphically (since they will never exist 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 independent
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 minimum
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 things will
'show through'. In other
words, you could call the wheel's 'Turn()' method directly. But in a real
aggregate system, everything
has new constraints which are defined by the system, not by the bits. You
cannot turn a tricycle's
whell without also turning the handlebars (at least if its working right.)
Aggregation via delegation deals with this issue while still allowing for
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 interfaces
is not useful. Its just that
its more useful when modelling 'optional behavior' type of stuff. Modelling
real world aggregation
is more often better served by aggregation and delegation, though it does
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
xml-dev: A list for W3C XML Developers. To post, mailto:xml-dev@ic.ac.uk
Archived as: http://www.lists.ic.ac.uk/hypermail/xml-dev/
To (un)subscribe, mailto:majordomo@ic.ac.uk the following message;
(un)subscribe xml-dev
To subscribe to the digests, mailto:majordomo@ic.ac.uk the following message;
subscribe xml-dev-digest
List coordinator, Henry Rzepa (mailto:rzepa@ic.ac.uk)
|