Is delegation just a route to obfuscation?

V

VisionSet

I've fallen in to a pattern of what feels like excessive delegation,
probably helped along academically.
Has anyone got any wise words on detecting when it is appropriate and when
it isn't? I'm aware of responsibility. It's just that the request usually
comes from one end of the application and the ultimate responsibility is at
the other!! And then you get code which is 90% passing the buck!
 
J

Jesper Nordenberg

VisionSet said:
I've fallen in to a pattern of what feels like excessive delegation,
probably helped along academically.

I've never seen a case of "excessive delegation", but often the
contrary. Is there even such a thing? Maybe if you could provide an
example of what you call "excessive delegation" it would be easier to
reason about.
Has anyone got any wise words on detecting when it is appropriate and when
it isn't?

I use delegation when I need to reuse implementation. You should
always use delegation when you want to add behaviour to some (unknown)
object. I use inheritance strictly as a "is a" glue, not for just
reusing implementation.

/Jesper Nordenberg
 
R

Roedy Green

And then you get code which is 90% passing the buck!

That's Java for you. The advantage is everything is loosely coupled.
You can replace the way something is done and guarantee all clients
use the new way because you never gave them direct access to the
lowest levels.
 
R

Roedy Green

Different types of object should only know about the things that directly
concern them and call the methods in those objects, but often this leads to
a whole chain of method calls where 90% of them do nothing other than
delegate thus bloating the code.

An example of this that drove me a little nuts was in two applications
that had complex screen displays with component within component
within component.

To send a message to some widget buried in there, logically I felt I
had to send it to the highest level who then passed it on down.
Similarly there were chains of listeners to pass information back out
dynamically.

I felt it was improper to expose the widget publicly, and the naming
structure to get to it.

Dealing with that was the hardest thing about writing the program.
Every time I wanted to do something I realised the thing that had a
reference to the object that could do it was N levels of indirection
away.

Made me long for the days of FORTRAN global COMMON.
 
H

H. S. Lahman

Original Post:
I've fallen in to a pattern of what feels like excessive delegation,
probably helped along academically.

Cohesion is very important in OO development because it is the basis of
logical indivisibility which is, in turn, the basis of peer-to-per
collaboration. Good cohesion usually requires the class abstraction be
quite simple.

Alas, entities in problem spaces other than the computing space tend not
to be simple. So we need to simplify them. There are are basically
only two techniques for doing that: subclassing and delegation.
Unfortunately, subclassing has some disadvantages.

One is that it is a static relation so it can't be modified without
touching the code. Delegation, though, can be modified through dynamic
instantiation of associations at run-time.

A more serious problem is that OO subclassing, unlike data modeling's
version, does not really resolve the cohesion problem. That's because
all subclass members are also members of the root superclass. Therefore
all of the subclass specializations are represented in the membership of
the root superclass. So large subclassing trees usually indicate a lack
of cohesion for the root superclass (i.e., the tree as a whole is
serving too many masters).

On the upside, OO subclassing has some advantages than more than
compensate for the disadvantages so long as the tree is fairly simple
and the context is right. One advantage is collecting commonality among
very similar entities. But the biggee is inclusion polymorphism that
allows one to substitute different behavior implementations
transparently at run-time. The entire GoF set of patterns is based upon
this characteristic.

The bottom line is that one should seek to use delegation over
subclassing except in those situations where subclassing truly shines.
Has anyone got any wise words on detecting when it is appropriate and when
it isn't? I'm aware of responsibility. It's just that the request usually
comes from one end of the application and the ultimate responsibility is at
the other!! And then you get code which is 90% passing the buck!

Use subclassing when there is a natural taxonomy in the problem space.
When in doubt mimic the problem space. In reality, though, behavior
taxonomies are extremely rare in most customer problem spaces, so this
effectively means data taxonomies.

Use subclassing when groups of entities are very similar but differ in
minor ways. Even then, look for way to employ parametric polymorphism
(i.e., express the differences in terms of data values rather than
specializations) instead. Also look for ways to separate out groups of
properties in terms of roles. Separation of roles may not eliminate
subclassing but it can often simplify it substantially (e.g., a huge
tree is refactored into two or more much smaller role trees). The GoF
State and Strategy patterns are classic examples of this sort of
simplification by role extraction.

Use subclassing when you need to substitute behaviors dynamically. If
you look closely at the GoF patterns they all share a common "pattern"
-- they all implement a simple association where participation in the
association is inherently dynamic (determined at run-time) and it is
complicated. IOW, the GoF patterns are reifications of relationships
that are too complicated to describe with simple associations.

Use subclassing to eliminate conditional relationships. Conditional
relationships require extra code to be written in every context where
the relationship is navigated. For example, a simple representation of
a hierarchical taxonomy is:

starts at 1 0..1 child of
[Tree] ----------------- [Node] ---------------+
0..1 root of | 0..* |
| parent of |
| |
+------------------+

One can eliminate all of the conditional relationships via:

* parent of
[Node] -------------------------+
A |
| |
+----------+------------+ |
| | |
[Leaf] [Non-Leaf] ---------+
A 1 child of
|
+-------+-------+
| | 1 starts at
[Intermediate] [Root] ---------------- [Tree]
base of 1

Because of the class declarations this will be more LOC but the number
of executable statements will be substantially fewer, which should
improve reliability. In most practical situations there will also be
other justifications for the more elaborate version (e.g., a Leaf may
have an item description in a POS application while the others don't).

Use delegation for everything else.

As far as your concern about lots of code to pass the buck is concerned,
that suggests something else is wrong. Typically delegation involves a
new class and a relationship. The collaborations should still be
peer-to-peer. That is, whoever would have accessed the property in the
original class would now navigate to the new class owning the property
and access it directly there. Basically one has originally:

[BigHonker]
+ doIt1
+ doIt2
+ doIt3
+ doIt4

which, after delegation, goes to

1 delegates to 1
[Honker] -------------------- [NewHonker]
+ doIt1 + doIt3
+ doIt2 + doIt4

IOW, you don't want the client to invoke BigHonker.doIt4 and have that
method just invoke NewHonker.doIt4; the client should invoke
NewHonker.doIt4 directly.

*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
(e-mail address removed)
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
(888)-OOA-PATH
 
V

VisionSet

Jesper Nordenberg said:
"VisionSet" <[email protected]> wrote in message

I've never seen a case of "excessive delegation", but often the
contrary. Is there even such a thing? Maybe if you could provide an
example of what you call "excessive delegation" it would be easier to
reason about.

Different types of object should only know about the things that directly
concern them and call the methods in those objects, but often this leads to
a whole chain of method calls where 90% of them do nothing other than
delegate thus bloating the code.
I use delegation when I need to reuse implementation. You should
always use delegation when you want to add behaviour to some (unknown)
object. I use inheritance strictly as a "is a" glue, not for just
reusing implementation.

Absolutely!

Actually I think this should be on comp.object

Original Post:
I've fallen in to a pattern of what feels like excessive delegation,
probably helped along academically.
Has anyone got any wise words on detecting when it is appropriate and when
it isn't? I'm aware of responsibility. It's just that the request usually
comes from one end of the application and the ultimate responsibility is at
the other!! And then you get code which is 90% passing the buck!
 
C

Cristiano Sadun

I've fallen in to a pattern of what feels like excessive delegation,
probably helped along academically.
Has anyone got any wise words on detecting when it is appropriate and
when it isn't? I'm aware of responsibility. It's just that the
request usually comes from one end of the application and the ultimate
responsibility is at the other!! And then you get code which is 90%
passing the buck!

Hm. The code doing the delegation consists usually of a reference to the
delegate object, plus a bridging method which usually doesnt do anything
more than "passing the buck".

In general, therefore, it doesnt make the code particularly unreadable,
especially if you use tricks like grouping together delegate references
(maybe using distinct private: sections in C++) and the bridging methods,
and use proper comments.

On the other hand, if your responsability chains are too long, you may
reconsider your design: unless the business process itself has extreme
depth, it might be that your model is too fragmented, and the excessive
delegation is just a symptom, not the disease.
 
I

Its Me

Roedy Green said:
Dealing with that was the hardest thing about writing the program.
Every time I wanted to do something I realised the thing that had a
reference to the object that could do it was N levels of indirection
away.

Made me long for the days of FORTRAN global COMMON.

You might also consider

a) dynamic binding (far better than global COMMON)
b) a more dynamic language (Ruby, Python, Smalltalk...) which allows
'catch-all' forwarding rather than individual explicit forwarding functions
 
R

Roedy Green

It is lot of like life in a Dilbertian bureaucracy where you must go
through channels to talk to other earthlings in another department.
You can't just phone them directly. At least you can't initiate a
direct conversation, even if you might talk directly after the channel
has been established.
 
R

Richard Riehle

Just as inheritance is not the
solution to every problem, neither is delegation.
For languages that directly support some form of
delegation, there are problems for which it is the
appropriate solution.

Delegation is handy, architecturally, because it does
not (when properly implemented) involve a call-return
model. For concurrency (e.g., in Ada) delegation is
especially powerful.

Every programming mechanism can be misused. It is
a matter of choosing the mechanism wisely.

Richard Riehle
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top