Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, monks. I ask your assistance.

I've been looking into updating some fairly old modules I have written, and, given some time to do so, look at redesigning them. And deciding to learn a better way to do things in general, decided to approach a easily solved problem, wondering what the better way is.

(Oh, I'm going to do a lot of things wrong. I'm pretty new to Moose, for one, and for another, this is design-related, so I'm taking shortcuts to demonstrate my thought processes.)

I have an application. It has a database connection.
package MyApp::DBConnection use Moose; has dbh => { is => 'ro' }; sub BUILD { #load the config from a config file, etc. #create the connection, set the handle. Etc, etc. } 1; package MyApp; use Moose; has dbConnection (is => 'ro', isa => 'MyApp::DBConnection', default => + sub { MyApp::DBConnection->new() }); 1;
Good so far. Kinda. So long as MyApp is simple, this works. But then we add MyApp::DB::User. It needs the database handle to run some queries.
package MyApp::DB::User; use Moose; has dbh => (is => 'ro', required => 1); sub runQuery { return $shift->dbh->selectrow_array("sp_msforeachtable 'SELECT * F +ROM \?'"); }
#someplace in MyApp sub doSomethingWithUser { my $self = shift; my $user = MyApp::DB::User->new({dbh => $self->DBConnection->dbh}) +; 1; }
MyApp::User(s) are created at runtime. So, there's several things I can do:
* pass the connection around when I create the dependent objects.
      That's what I'm doing above. It works. It gets uglier when MyApp::DB::User needs to create MyApp::DB::User::SomethingElse, which also needs the database handle.
* create a DBConnection singleton.
     Again, it works. I could easily make the handle in MyApp::DBConnection a method that returns the same $dbh, for example, and call MyApp::DBConnection->dbh when I need it. I see a lot of .NET code that does this.
* ...Something else?
I was looking into dependency injection (with Bread::Board), but that doesn't seem to be right when I'm creating the objects at runtime.

Can anyone shed any light into modern (or post-modern) ways of handling this problem?

Replies are listed 'Best First'.
Re: passing objects to dependancies
by doug (Pilgrim) on Feb 11, 2010 at 21:33 UTC

    I'm not sure that I'm understanding you. You need your database connection, but don't want to pass is as a parameter all over the place. That is usually done with a factory object. That factory object is a singleton (aka - global) and you ask it for a DB connection. It returns the same MyApp::DBConnection object to everyone. Your code snippet becomes

    my $self = shift; my $connection = MyApp::ConnectionFactory->connection(); my $user = MyApp::DB::User->new({dbh => $connection->dbh()});

    Is this even close to what you want?

    Also, that { dbh => $value } thing is ugly. Use BUILDARGS so that the constructor (aka 'new') takes a single arg.

    sub BUILDARGS { my ($class, $dbh) = @_; { dbh => $dbh }; }

    I think that is much easier on the eyes. And instead of creating all the connections at startup time, I'd make 'em lazy and only have them done when necessary.

    Good luck.

    - doug