Dependency Injection 2014

14
12/12/2014 1 Steven van Deursen cuttingedge.it/blogs/steven @dot_net_junkie [email protected] Dependency Injection Dependency injection is a software design pattern that implements inversion of control and allows a program design to follow the dependency inversion principle.Source: en.wikipedia.org/wiki/Dependency_injection

Transcript of Dependency Injection 2014

12/12/2014

1

Steven van Deursen

cuttingedge.it/blogs/steven

@dot_net_junkie

[email protected]

Dependency Injection

“Dependency injection is a software

design pattern that implements

inversion of control and allows a

program design to follow the

dependency inversion principle.”

Source:

en.wikipedia.org/wiki/Dependency_injection

12/12/2014

2

Inversion of Control

• Describes the interaction between code and a framework

• IoC does not describe how the interaction takes place.

• It’s so common; we don’t think about it anymore.

The SOLID principles

•Single responsibility principle

•Open/closed principle

•Liskov substitution principle

•Interface segregation principle

•Dependency inversion principle

12/12/2014

3

Dependency Inversion Principle

“A. High-level modules should not

depend on low-level modules. Both

should depend on abstractions.

B. Abstractions should not depend on

details. Details should depend on

abstractions.”

Source:

en.wikipedia.org/wiki/Dependency_inversion_principle

Dependency Inversion Principle

Example: the “Copy” program

12/12/2014

4

Dependency Inversion Principle

Example: the “Copy” program

“A. High-level modules should not

depend on low-level modules. Both

should depend on abstractions.

B. Abstractions should not depend on

details. Details should depend on

abstractions.”

Dependency Inversion Principle (DIP)

The problem of class coupling

•Maintainability

•Extendibility

•Reusability

•Testability

•Parallel development

“A. High-level modules should not

depend on low-level modules. Both

should depend on abstractions.

B. Abstractions should not depend on

details. Details should depend on

abstractions.”

12/12/2014

5

static class CameraOperator{public:

static Snapshot Operate(){

CameraPosition position = DetermineNextCameraPosition();

return RaytracingCamera::TakeSnapshot(position);}

static CameraPosition DetermineNextCameraPosition(){

time_t currentTime = time(NULL);

// Assume some complex time dependent calculation.return CameraPosition();

}};

DIP Violations

static class CameraOperator{public:

static Snapshot Operate(){

CameraPosition position = DetermineNextCameraPosition();ICamera* camera = ...;return camera->TakeSnapshot(position);

}

static CameraPosition DetermineNextCameraPosition(){

ITimeProvider* timeProvider = ...;time_t currentTime = timeProvider->GetCurrentTime();// Assume some complex time dependent calculation.return CameraPosition();

}};

Applying DIP

12/12/2014

6

Service Locator

static class CameraOperator{public:

static Snapshot Operate(){

CameraPosition position = DetermineNextCameraPosition();

ICamera* camera = Locator::Get<ICamera>();return camera->TakeSnapshot(position);delete camera;

}

static CameraPosition DetermineNextCameraPosition(){

ITimeProvider* timeProvider = Locator::Get<ITimeProvider>();time_t currentTime = timeProvider->GetCurrentTime();delete timeProvider;

// Assume some complex time dependent calculation.return CameraPosition();

}};

Service Locator

12/12/2014

7

Service Locator

Advantages

•Easy to grasp

• Easy to get started with in a legacy application

Service Locator

Disadvantages

• DIP violation in itself

•Can’t work without the Locator

•Context unclear from perspective of the locator

•Hard to test

•No compile-time support

•Dependencies unclear

12/12/2014

8

Service Locator is an anti-pattern

Dependency Injection

12/12/2014

9

class CameraOperator{private:

ITimeProvider* timeProvider;ICamera* camera;

public:CameraOperator(ITimeProvider* timeProvider, ICamera* camera){

this->timeProvider = timeProvider;this->camera = camera;

}

Snapshot Operate(){

CameraPosition position = DetermineNextCameraPosition();return this->camera->TakeSnapshot(position);

}

CameraPosition DetermineNextCameraPosition(){

time_t currentTime = this->timeProvider->GetCurrentTime();return CameraPosition();

}};

Dependency Injection

Dependency Injection

Advantages

• Dependencies clear

•Compile-time support

•Easy to spot SRP violations

•No more dependency with Locator.

12/12/2014

10

Dependency Injection

Disadvantages

•We’ll get to that…

class MovieScene{public:

void RecordScene(){

SystemTimeProvider* timeProvider = new SystemTimeProvider();RaytracingCamera* camera = new RaytracingCamera();CameraOperator* cameraOperator =

new CameraOperator(timeProvider, camera);MpegFileRecorder* recorder =

new MpegFileRecorder("c:\\movies\\di_bloopers.mpg");

while (!wholeSceneRecorded) {Snapshot snapshot = cameraOperator->Operate();recorder->Append(snapshot);

}

delete recorder;delete cameraOperator;delete camera;delete timeProvider;

}};

Dependency Injection

12/12/2014

11

class MovieScene{private:

ITimeProvider* timeProvider;ICamera* camera;IRecorder* recorder;

public:MovieScene(ITimeProvider* provider, ICamera* camera, IRecorder* recorder){

this->timeProvider = provider;this->camera = camera;this->recorder = recorder;

}

void RecordScene(){

CameraOperator* cameraOperator =new CameraOperator(this->timeProvider, this->camera);

while (!wholeSceneRecorded) {Snapshot snapshot = cameraOperator->Operate();this->recorder->Append(snapshot);

}

delete cameraOperator;}

};

Dependency Injection

class MovieScene{private:

ICameraOperator* cameraOperator;IRecorder* recorder;

public:MovieScene(ICameraOperator* cameraOperator, IRecorder* recorder){

this->cameraOperator = cameraOperator;this->recorder = recorder;

}

void RecordScene(){

while (!wholeSceneRecorded) {Snapshot snapshot = this->cameraOperator->Operate();this->recorder->Append(snapshot);

}}

};

Dependency Injection

12/12/2014

12

int _tmain(int argc, _TCHAR* argv[]){

// Composition RootITimeProvider* timeProvider = new SystemTimeProvider();ICamera* camera = new RaytracingCamera(1280, 1024);ICameraOperator* operator =

new CameraOperator(timeProvider, camera);

IRecorder* recorder =new MpegFileRecorder("c:\\movies\\di_successStories.mpg");

MovieScene* movieScene = new MovieScene(cameraOperator, recorder);

movieScene->RecordScene();

delete movieScene;delete recorder;delete cameraOperator;delete camera;delete timeProvider;

return 0;};

Composition Root

ITimeProvider* g_timeProvider = new SystemTimeProvider();

int _tmain(int argc, _TCHAR* argv[]){

while (true) // Simulate requests{

Request<MovieScene>* request = CreateScene(new WireframeCamera(375, 300), new ScreenViewer());

MovieScene* scene = request->Root;scene->RecordScene();delete request;

}

return 0;};

Request<MovieScene>* CreateScene(ICamera* camera, IRecorder* recorder){

Request<MovieScene>* request = new Request<MovieScene>();

request->Root = new MovieScene(request->Add(new CameraOperator(

g_timeProvider, request->Add(camera))),

request->Add(recorder));

return request;};

Composition Root

12/12/2014

13

Composition Root

Advantages of centralizing creation of object graphs

•Not doing so fails DIP

•Easier to reason about concurrency and thread-safety

•Easier to reason about resource management.

Dependency Injection

Disadvantages?

•Takes time to master

•Not easy to apply in legacy systems

12/12/2014

14

Books!

•Mark Seemann

•Roy Osherove

•Jeff Langr

•Robert C. Martin

Steven van Deursen

cuttingedge.it/blogs/steven

@dot_net_junkie

[email protected]