Re: [CDBI] Different subclasses for one table / Factory Pattern?

Oliver Jeeves <[email protected]>
Newsgroups gmane.comp.lang.perl.modules.class-dbi
Message-ID <[email protected]>
Stephan Brunner wrote:
> I wrote:
>>> You have probably come up with a solution by now, I'm sure.  Let us
>>> know what you ultimately came up with.
>> Hmm, well, yes, somehow... But I didn't have the time to implement my
>> solution, and, in my experience, the solution might change during
>> implementation;-)
>>
>> For the next weeks, I'm away from the computer, so please be patient. But I
>> will let you know and I'm also interested in the discussion!
> 
> Here I am back again.
> Looking at Oliver's episodes, I'm quite happy about the solution I came up 
> with: I kept everything related to different-subclasses-per-table away from 
> CDBI.
> 
> I introduced a class FileType with several subclasses (FileType::JPG, 
> FileType::AVI etc.). To the class representing the database table ("files"), 
> I added an object property "type", wich keeps an object of the relevant 
> subclass of FileType. Looks like so:
> 
> package File;
> use base 'Class::DBI';
> # ...
> sub type {
>     my $self = shift;
>     if (not exists $self->{type}) {
>         $self->{type} = FileType->new($self);
>     }
>     return $self->{type};
> }
> 
> package FileType;
> sub new { 
>     shift; # throw class away
>     my $file = shift;
>     my $name = $file->name();
> 
>     my $class = undef;
>     my @classes = qw/JPG WAV AVI/;
> TRY: foreach my $try_class (@classes) {
>         $try_class = __PACKAGE__ . '::' . $try_class;
>         # passing $name explicitly avoids the call of $file->name in
>         # every is_member:
>         if ($try_class->is_member($name, $file)) {
>             $class = $try_class;
>             # first try_class saying "yes, $file is_member!" gets selected
>             last TRY;
>         }
>     }
>     if (not defined $class) {
>         $class = __PACKAGE__ . '::Unknown';
>     }
> 
>     # create and return an object of the selected class;
>     # keep a reference to the $file object for later use
>     my $self = bless { file => $file }, $class;
>     return $self;
> }
> # ...
> 
> package FileType::JPG;
> # for example
> sub is_member {
>     shift;
>     my ($name, $object) = @_;
>     return ($name =~ /.jpe?g$/i) ? 1 : 0;
> }
> 
> 
> One big drawback is the additional method calls I get. To rotate a jpg, for 
> example, I call $file->type->rotate(), as rotate is a method of 
> FileType::JPG.
> And, even worse, in FileType::JPG::rotate (called on the FileType object 
> stored in $file->type), I call $self->file() to get the file that actually 
> will be rotated. To avoid this, I would have to call 
> $file->type->rotate($file), which also looks strange to me.
> 
> Well, this obviously is no perfect OO design. On the other hand, it is quite 
> clear and obvious in how it works as I'm not using nor overriding any CDBI 
> internals.
> Anyway, I'm not perfectly happy about it, so any comments still very welcome!
> 
> Regards,
> Stephan

Calling $self->file() in a method doesn't seem at all bad, so long as
you're storing a reference to your file and not having to look it
up/construct it again.

Rather then defining a new method 'type' which makes the assumption that
CDBI objects are hashrefs (which that are, and is unlikely to change,
but still...), would it not be better to just use a has_a relationship
with your class?

package File;
use base 'Class::DBI'

__PACKAGE__->columns(Essential => qw/id data/);
__PACKAGE__->has_a(data => 'FileType',
	inflate => 'new');

Or something similar.

-Oli

_______________________________________________
ClassDBI mailing list
ClassDBI-Ra3b/[email protected]
http://lists.digitalcraftsmen.net/mailman/listinfo/classdbi
signature.asc (application/pgp-signature, 189 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)

iD8DBQFFCl6lSbWXajvTQ+URAsD5AJ4yDMaB0kAD74vYOeq5y2QUzwPS5wCfWlmi
gscx/62m0KnQmR1QRqrUdw8=
=W3x+
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.