introducing dependency injection - akrabat.com · introducing dependency injection rob allen...

42
Introducing Dependency Injection Rob Allen October 2013

Upload: trinhkien

Post on 09-Apr-2018

218 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

IntroducingDependency Injection

Rob AllenOctober 2013

Page 2: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

I make websites19ft.com

Page 3: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Dependency Injection enables loose coupling andloose coupling makes code more maintainable

Mark Seemann

Page 4: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

We’re actually talking about loose coupling today

Page 5: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Coupling

Page 6: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Pros and cons:Pros:

• Very simple to use

Cons:

• Tight coupling

• Cannot test Letter in isolation• Cannot change $paper

Page 9: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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

Page 10: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Inject the dependency!

Page 13: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

This is also known as

Inversion of Control

Page 15: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Dependency Injection

That’s it; we’re done!

Page 17: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

NoteToo many constructor parameters is a code smell

Two-phase construction is Bad(TM)

Page 19: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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

Page 20: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Usage$container = new LetterContainer()

$letter = $container->getLetter();

Page 24: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Handle configurationclass LetterContainer

{

protected $params;

public function __construct(array $params)

{

$this->params = $params;

}

Page 25: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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

Page 31: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Pimple usage$container = new Pimple();

$letter = $container['letter'];

Page 33: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Recommendation• Hold configuration separately• Create each each object separately

Page 36: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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 - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

ZendDi configurationbeforehand:

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

array(

'size' => 'A4',

)

);

when retrieving:

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

Page 38: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Service Locationclass Letter

{

protected $paper;

public function __construct($locator)

{

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

}

}

Page 39: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

Service Location• Application pulls its dependencies in when it needs

them• Still decouples concrete implementation of Paper

from Letter

Page 40: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

RecapDependency injection promotes:

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

Page 41: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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

James Shore

Page 42: Introducing Dependency Injection - akrabat.com · Introducing Dependency Injection Rob Allen October 2013. ... • SymfonyContainer - part of Symfony2 • ZendDi & ZendServiceManager

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

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