Constructing my objects via IoC framework (Bread::Board) I found quite typical pattern in my code.
Simple example: I have a Synchronizer object (for copying some files).
Synchronizer uses Transport object (SFTP client maybe) to transfer physical files.
If Transport instance is same for whole lifetime of Synchronizer,
it can be made into an attribute and objects can be constructed
via simple constructor injection:
{
package Synchronizer;
use Moose;
has transport => (is => 'ro', required => 1);
}
{
package Transport;
use Moose;
}
use Bread::Board;
my $root = container Root => as {
service transport => ( class => 'Transport' );
service synchronizer => (
class => 'Synchronizer',
dependencies => wire_names('transport'),
lifecycle => 'Singleton',
);
};
my $synchronizer = $root->resolve( service => 'synchronizer' );
warn $synchronizer->transport;
warn $synchronizer->transport;
But what if I want that every call of $synchronizer->transport returns new instance of Transport,
i.e. whenever $synchronizer->transport is called transport service is reevaluated
(->get is called)?
The only way I found how to was to create new (concrete) BBSynchronizer class
and wire the Bread::Board service into its instances. Something like:
{
package Transport;
use Moose;
}
{
package Synchronizer;
use Moose;
sub transport {...} # unimplemented
}
{
package BBSychronizer;
use Moose;
extends 'Synchronizer';
has __transport_service => ( is => 'ro', handles => {transport => 'get'} );
}
use Bread::Board;
my $root = container Root => as {
service transport => ( block => sub { return Transport->new; }, );
service synchronizer => (
class => 'BBSychronizer',
block => sub {
my $s = shift;
return $s->class->new(__transport_service => $s->fetch('transport'));
},
);
};
my $root2 = container Root => as {
service transport => ( block => sub { return Transport->new; }, );
service __transport_service =>
( block => sub { shift()->fetch('transport'); } );
service synchronizer => (
class => 'BBSychronizer',
dependencies => wire_names('__transport_service'),
);
};
my $synchronizer = $root->resolve( service => 'synchronizer' );
my $synchronizer2 = $root->resolve( service => 'synchronizer' );
warn $synchronizer2->transport;
warn $synchronizer2->transport;
I slightly prefer second solution, where synchronizer is created via simple constructor injection.
The __transport_service seems like lazy alias where get on alias returns the aliased
service not its value.
Maybe the whole topic is more IoC than Bread::Board related and the solution obvious but I appreciate any comments.
Roman Daniel
|