OO Architecture redux
[email protected] (Tim Bunce) Thu, 29 Sep 2005 19:35:26 +0100
| Newsgroups | perl.dbi2.dev |
|---|---|
| Message-ID | <[email protected]> |
Okay, so where have we got to...
Subclassing:
- Useful for adding/changing behaviour in a driver-indepandant way
- Hard (bordering on impossible) to use multiple subclasses at once.
More Classes (Roles):
- "The DBI" will be less of a single entity than it was before.
So "subclassing the DBI" will become less meaningful.
It'll be "subclassing the DBI <foo>" where foo can be
connections, statements, logging, driver management etc. etc.
Roles:
- Perl6 Roles (http://dev.perl.org/perl6/doc/design/syn/S12.html#roles)
will be useful in several ways
- APIs to the multiple classes within DBI will be defined by Roles.
- Alternative implementations can be substituted if they 'do' the Role
(here the Role is acting like a Java Interface).
- Handles will have references to the objects that provide certain
services, such as logging, so alternative implementations can be
substituted on a per-handle basis.
- As an alternative to manipulating the internals of the handle,
applications could compose new anonymous classes by mixing multiple
roles. Here's an extract from the roles docs url above:
Run-time mixins are done with does and but. The does binary operator
is a mutator that derives a new anonymous class (if necessary) and binds
the object to it:
$fido does Sentry
The does operator returns the object so you can nest mixins:
$fido does Sentry does Tricks does TailChasing does Scratch;
Unlike the compile-time role composition, each of these layers on a
new mixin with a new level of inheritance, creating a new anonymous
class for dear old Fido, so that a .chase method from TailChasing hides
a .chase method from Sentry.
- As a result of this ability I'd expect there to be many CPAN modules
offering roles that can be composed into handles in this way.
- Choosing between subclassing components of the DBI internals
or compile-time/run-time subclassing of handles via role mixins
will depend on the particular functionality required.
At this point I think it's time to start sketching out what the roles
look like and what the guts of a handle looks like. Then we can reduce
the degree of generality and vagueness we're dealing with at the moment.
(But I might distract you with a thread on DSNs first ;-)
To HAVE-A handle or to BE-A handle, that is the question:
So, where does all that leave us with our original question?
Should an applications $dbh be a driver $dbh, blessed into some random
class within the driver, or should it be a wrapper object (provided by
the DBI) with a fixed class (like DBI::db)?
The former is faster, avoiding the need for re-dispatching method calls,
but the latter makes subclassing easier.
I'm thinking along the lines of "make subclassing possible rather than
easy, and then encapsulate it so it's easy again" :)
Basically go with "DBI handle IS-A driver handle" but also supply a
module that provides a transparent 'proxy' object which HAS-A driver
handle. Then anyone wanting to subclass the DBI would use that as the
base class. (I know, I should say "subclass the DBI" without qualifying
it but I'll duck that for now.)
The win is that the price for re-dispatching the method calls is only
paid by those who want to use it.
Tim.