[Israel.pm] An OOP Pattern Discovered by Accident

Oded Arbel oded-linux at typo.co.il
Fri Jan 26 18:03:19 PST 2007


On Fri, 2007-01-26 at 18:15 +0200, Shlomi Fish wrote:
> [...skipping a long naval gazing...]
> Thinking about it, I realised one can consciously use this scheme by working 
> on an accessor and then over-riding this accessor in the derived class to 
> point to the accessor of the containing class.
> 
> So we can do:
> 
> class Account
> {
> 	function account() { return self; }
> 	# Other functions that operate on account.
> }
> 
> 
> class B inherit from Account
> {
> 	Account myaccount;
> 
> 	function account() { return myaccount; }
> 
> 	# We get the functions for free.
> }

It looks like you are trying to do a "delegate" design pattern, but
being extra lazy about it - so you are saying, that instead of writing
delegate methods, one can implement a delegate scaffolding in the parent
and be done with it ? I'm afraid its not that easy: Delegation is often
used in wrappers that delegate some functionality to the wrapped
(contained) implementation. This common scenario cannot be written using
your method because:
1. The implementor of the wrapper code uses a delegate method because
she can't change the wrapped code - either due to insufficient rights,
or because it would break other dependent code. The standard delegate
pattern allows the implementor to delegate to code that was not designed
with delegation in mind, while your approach demands that every class
that may ever be delegated to must be specifically written with the
scaffolding in place.
2. Delegation is commonly done to override some functionality of the
delegated instance while preserving most of the original functionality,
but using your method its a "whole or nothing" approach: with the
scaffolding in place everything is delegated and the wrapper class
cannot implement its own functionality.

Another thing which I don't like about your code, is that it makes
calling code unnecessarily contrived:

Normally, to get the account name I would call:

account->getName() 

but with your mechanism in place, I would have to 

account->account()->getName()

and thus for every call. More over, in a class expanding on account with
additional calls, the user would need to remember which calls are
implemented by the Account class and which are implemented by the
inheriting class, and call each using a different convention:

account->account()->getName()
account->getSpecializedName()

throwing abstraction and encapsulation out the window, while making life
harder for everyone in the process.

I appreciate you not wanting to "waste" a lot of time writing seemingly
unnecessary delegate methods instead of getting rid of it all by a
simple change to the top-most class, but IMHO that doesn't solve any
real problem while creating a slew of other problems. I think your
approach above can be labeled as an "anti-pattern" (look it up). The
apparent problem of too much boiler-plate can be solved much easier by
automatic code generation (as is available in many modern development
environments).

--
Oded
::..
The difference between the right word and the almost right word is the
difference between lightning and the lightning bug.
                -- Mark Twain





More information about the Perl mailing list