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

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.