Like database normalization, there are times that it's okay to break the rules when the rules conflict with your goals. In this case (though I would probably go with Class::DBI), you have a situation exactly like one that I had a few months ago. I solved it by breaking the rules.
sub new { my $proto = shift; my $class = ref( $proto ) || $proto; my $self = { 'group_id' => 0, 'name' => '', '_members' => [], }; bless( $self, $class ); return $self; } sub get_members { my $self = shift; my $members = $dbh->selectcol_arrayref('SELECT person_id FROM group +_member WHERE group_id = ' . $self->id()); foreach my $person_id ( @{$members} ) { push( @members, Person->new($person_id) ); } return \@members; }
You're making a call to new() for every set of data. With a large dataset, this can get expensive. While the following results in duplicated code, it can be much faster (by using this technique I had an identical subroutine that returned instantly versus a several second delay).
sub get_members { my $self = shift; my $class = ref $self; my $group_id = $self->id; my $quoted_group_id = $dbh->quote($group_id); my $members = $dbh->selectcol_arrayref(<<" END_SQL"); SELECT person_id FROM group_member WHERE group_id = $quoted_group_id END_SQL foreach my $person_id ( @{$members} ) { my $person = bless { group_id => $group_id, person_id => $person_id, name => '', _members => [], }, $class; push @members => $person; } return \@members; }
(It's just a rough demonstration of the technique. You'll need to customize it to your needs, if you use it.)
Note that we have duplicated the constructor's behavior. Do not do this unless you have a known performance issue. Having duplicated code like this should only be done for very clear cut reasons. It also need documentation to help the programmer find where the functionality is duplicated and understand why it was done lest you have someone's clever refactoring kill your code's performance.
Final note, here's how I would rewrite your constructor:
sub new { my $class = shift; my $self = { 'group_id' => 0, 'name' => '', '_members' => [], }; bless( $self, $class ); return $self; }
There is no need for the ref $proto || $proto in your constructor. Just leave it out unless you have a very specific reason to do so. It's just clutter. And yes, I know some tutorials bundled with Perl make this mistake :)
Cheers,
Ovid
New address of my CGI Course.
In reply to Re: Battling with OOP performance
by Ovid
in thread Battling with OOP performance
by Evil Attraction
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |