introducing dependency injection · dependency injection container • creates objects on demand...

42
Introducing Dependency Injection Rob Allen November 2013

Upload: others

Post on 24-May-2020

21 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

IntroducingDependency Injection

Rob AllenNovember 2013

Page 2: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

I make websites19ft.com

Page 3: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Dependency Injection enables loose coupling andloose coupling makes code more maintainable

Mark Seemann

Page 4: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

We’re actually talking about loose coupling today

Page 5: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Coupling

Page 6: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Benefits of loose coupling• Maintainability - Classes are more clearly defined• Extensibility - easy to recompose application• Testability - isolate what you’re testing

Page 7: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

A worked exampleClass A needs class B in order to work.

class Letter

{

protected $paper;

public function __construct()

{

$this->paper = new WritingPaper();

}

}

// usage:

$letter = new Letter();

$letter->write("Dear John, ...");

Page 8: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Pros and cons:Pros:

• Very simple to use

Cons:

• Tight coupling

• Cannot test Letter in isolation• Cannot change $paper

Page 9: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

The problem with coupling• How do we change the paper size?• How do we change the type of paper?

Page 10: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Method parameters?class Letter

{

protected $paper;

public function __construct($size)

{

$this->paper = new WritingPaper($size);

}

}

// usage:

$letter = new Letter('A4');

$letter->write("Dear John, ...");

Page 11: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Use a Registry?class Letter

{

protected $paper;

public function write($text)

{

$paper = Zend_Registry::get('paper');

return $paper->placeWords($text);

}

}

// usage:

Zend_Registry::set('paper', new AirmailPaper('A4'));

$letter = new Letter();

$letter->write("Dear John, ...");

Page 12: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Inject the dependency!

Page 13: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Injectionclass Letter

{

protected $paper;

public function __construct($paper)

{

$this->paper = $paper;

}

}

// usage:

$letter = new Letter(new WritingPaper('A4'));

$letter->write("Dear John, ...");

Page 14: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

This is also known as

Inversion of Control

Page 15: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Pros and cons:Pros:

• Decoupled $paper from Letter:

• Can change the type of paper• Natural configuration of the Paper object

• Can test Letter independently

Cons:

• Burden of construction of $paper is on the user

Page 16: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Dependency Injection

That’s it; we’re done!

Page 17: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Types of injectionConstructor injection:

$letter = new Letter($paper);

Property injection:

$letter = new Letter();

$letter->paper = $paper;

Setter injection:

$letter = new Letter();

$letter->setPaper($paper);

Page 18: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

NoteToo many constructor parameters is a code smell

Two-phase construction is Bad(TM)

Page 19: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Rule of thumb• Constructor injection for required dependencies• Setter injection for optional dependencies

Page 20: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

How about usage?$paper = new AirmailPaper('A4');

$envelope = new Envelope('DL');

$letter = new Letter($paper, $envelope);

$letter->write("Dear John, ...");

Setup of dependencies gets tedious quickly

Page 21: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Dependency Injection Container

A DIC is an object that handles the creation of objectsand their dependencies for you

Dependency resolution can be automatic or configured

DICs are optional

Page 22: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Write a simple containerclass LetterContainer

{

public function getLetter()

{

$paper = new AirmailPaper('A4');

$envelope = new Envelope('DL');

$letter = new Letter($paper, $envelope);

return $letter;

}

}

Page 23: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Usage$container = new LetterContainer()

$letter = $container->getLetter();

Page 24: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Handle configurationclass LetterContainer

{

protected $params;

public function __construct(array $params)

{

$this->params = $params;

}

Page 25: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

cont… public function getLetter()

{

$paper = new AirmailPaper(

$this->params['paper.size']);

$envelope = new Envelope(

$this->params['envelope.size']);

$letter = new Letter($paper, $envelope);

return $letter;

}

}

Page 26: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Usage// usage:

$container = new LetterContainer(array(

'paper.size' => 'A4',

'envelope.size' => 'DL',

))

$letter = $container->getLetter();

Now, it’s easy to change parameters of the dependentobjects

Page 27: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Shared objectsclass LetterContainer

{

protected $shared;

// ...

public function getLetter()

{

if (!isset(self::$shared['letter'])) {

// ... create $letter as before ...

self::$shared['letter'] = $letter;

}

return self::$shared['letter'];

}

}

Page 28: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Dependency Injection Container

• Creates objects on demand• Manages construction of an object’s dependencies• Separates of configuration from construction• Can allow for shared objects

However:

Writing and maintaining a container class by hand istedious!

Page 29: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Available DICsDon’t reinvent the wheel

• Pimple by Fabien Potencier• Dice by Tom Butler• SymfonyContainer - part of Symfony2• ZendDi & ZendServiceManager - part of ZF 2

Page 30: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Pimple• Easy to use• Small: only 70 lines of PHP• Configured manually

Page 31: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Pimple$container = new Pimple();

$container['letter'] = function ($c) {

$paper = new AirmailPaper('A4');

$envelope = new Envelope('DL');

$letter = new Letter($paper, $envelope);

return $letter;

};

Page 32: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Pimple usage$container = new Pimple();

$letter = $container['letter'];

Page 33: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

More typically$container = new Pimple();

$container['paper.size'] = 'DL';

$container['envelope.size'] = 'DL';

$container['paper'] = function ($c) {

$size = $c['paper.size'];

return new AirmailPaper($size);

};

$container['envelope'] = function ($c) {

$size = $c['envelope.size'];

return new Envelope($size);

};

Page 34: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

cont…$container['letter'] = function ($c) {

$paper = $c['paper'];

$envelope = $c['envelope'];

return new Letter($paper, $envelope);

};

Usage is identical:

$container = new Pimple();

$letter = $container['letter'];

Page 35: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Recommendation• Hold configuration separately• Create each each object separately

Page 36: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Automatic resolutionclass Letter

{

protected $paper;

public function __construct(AirmailPaper $paper)

{

$this->paper = $paper;

}

}

Usage:

$di = new Zend\Di\Di();

$letter = $di->get('Letter');

Page 37: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

ZendDi configurationbeforehand:

$di->instanceManager()->setParameters('AirmailPaper',

array(

'size' => 'A4',

)

);

when retrieving:

$letter = $di->get('Letter', array('size' => 'A4'));

Page 38: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Service Locationclass Letter

{

protected $paper;

public function __construct($locator)

{

$this->paper = $locator->get('paper');

}

}

Page 39: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Service Location• Application pulls its dependencies in when it needs

them• Still decouples concrete implementation of Paper

from Letter

Page 40: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

RecapDependency injection promotes:

• loose coupling• easier testing• separation of configuration from usage

Page 41: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

“Dependency Injection” is a 25-dollar term for a5-cent concept.

James Shore

Page 42: Introducing Dependency Injection · Dependency Injection Container • Creates objects on demand • Manages construction of an object’s dependencies • Separates of configuration

Thank you!https://joind.in/9263

Rob Allen - http://akrabat.com - @akrabat