Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
137 lines (101 sloc) 3.47 KB
- Dependency injection : __ ... in perl
- First... IoC :
- Lets get this out of the way first
- Control = rm -rf dir
- Inverse = rm -ri dir
- IoC = code asks for help
- DI?
- Dependency injection (DI) is an OO in technique that indicates to a part of a program which other parts it can use.
# in short DI is a lable from OO land, to refer to a practice of being able to shove in something from the outside.
- non-DI [code]->{dep}
- DI [code]<-{dep}
# ... well that's abstract and super fancy sounding! Let's take a look at a common example:
- ORM-ish EXAMPLE
# Lets say we have some ORM thing (no not DBIx::Class)
my $obj = Object->new();
my $val = $obj->find(this=>'that');
# Lets take a peek under the hood for 'find'
sub find {
my $self = shift;
$self->d->selectall_arrayref(
$self->qbuild( from => 'SomeTable'
, where=> {@_} # our input
)->dbi #
,{Slice=>{}}
);
}
# ok so all find does is take input, toss off to some "make SQL magic thing" (that we will be avoiding for now) and then calling some 'd' thing that appears to be a DBI object... Lets look further
- non-DI way to define 'd'
sub d {
require DBI;
DBI->connect(...);
}
- DI by the books
has d =>
is => 'ro',
isa => 'DBD::db',
required => 1,
;
- Happy middle ground
has d =>
is => 'ro',
isa => 'DBD::db',
default => sub{
require DBI;
DBI->connect(...)
},
;
# Looks like it's just a simple Moose Attribute, because it is. But the interesting thing here is that it stores an object.
- what does this give us?
my $obj = Object->new(d=>DBI->connect(...));
my $val = $obj->find(this=>'that');
- TADA! that's DI.
# honestly, this is all that fancy lable means.
- Advantages? :
- testing!
# Also, now that we have super generic objects testing DB driven code is cake as you just swap out the DB:
my $test_db = DBI->connect(...),
my $obj = Object->new(d=>$test_db);
is $obj->find(...), 'something'; #never touches live data
- reuse via abstraction
# First and foremost this is a way of thinking that will allow you to further re-use your code as you are building patterns for solutions that make only vague assumptions on the details.
# Let's take a look at our find sub again
sub find {
my $self = shift;
$self->d->selectall_arrayref(
$self->qbuild( from => 'SomeTable'
, where=> {@_} # our input
)->dbi
,{Slice=>{}}
);
}
# So we have a hardcoded value for the table name, lets fix that because this function now is tightly bound to a specific aspect.
has table =>
is => 'ro',
isa => 'Str',
default => 'SomeTable'
;
sub find {
my $self = shift;
$self->d->selectall_arrayref(
$self->qbuild( from => $self->table
, where=> {@_} # our input
)->dbi
,{Slice=>{}}
);
}
# now again we have a hook that is accessable from the outside to alter the behavor for find
my $obj = Object->new(table => 'OtherTable', d => DBI->connect(...));
my $val = $obj->find(...);
# So wait a sec... we just created a very basic 'table object' that we can now pass it just about anything and we get what we want... yup Bingo.
package My::Table;
use Moose;
extends 'Object';
has '+table' => default => 'Table';
1;
- Disadvantages?:
- Complexity
printf q{table has %d rows}, DBI->connect(...)->selectcol_arrayref('SELECT count(*) from table')->[0];
- Confusion
# just like most things perl... it gives you rope and expects you to be responsible
my $table = My::Table->new(table=>'other');