35
DEPENDENCY INJECTION & INVERSION OF CONTROL

DEPENDENCY INJECTION & INVERSION OF CONTROL. WHAT’S GOING TO BE COVERED Quick intro to C# for Java developers Dependency Injection Inversion of Control

Embed Size (px)

Citation preview

DEPENDENCY INJECTION &

INVERSION OF CONTROL

WHAT’S GOING TO BE COVERED

• Quick intro to C# for Java developers

• Dependency Injection

• Inversion of Control

• Containers

• Castle Windsor

C# FOR JAVA DEVELOPERS

• Most of this lecture is going to use C#

• DI is possible with any object-oriented language

• IoC requires a container

C# FOR JAVA DEVELOPERS

Java C#public class Car{

private Engine engine;private string registration;private int windowCount;

public Car(){

this.engine = new Engine();this.registration = "SW14ABC";this.windowCount = 6;

}}

public class Car {private Engine engine;private String registration;private int windowCount;

public Car() {this.engine = new Engine();this.registration = "SW14ABC";this.windowCount = 6;

}}

C# FOR JAVA DEVELOPERS

Java C#private Engine engine;private string registration;

public Engine Engine{

get{

return this.engine;}set{

this.engine = value;}

}

public String Registration{

get{

return this.registration;}

}

private Engine engine;private String registration;

public Engine getEngine() {return this.engine;

}

public void setEngine(Engine engine) {this.engine = engine;

}

public String getRegistration() {return this.registration;

}

C# FOR JAVA DEVELOPERS

Java C#private string registration;

public Engine Engine { get; set; }

public String Registration{

get{

return this.registration;}

}

private Engine engine;private String registration;

public Engine getEngine() {return this.engine;

}

public void setEngine(Engine engine) {this.engine = engine;

}

public String getRegistration() {return this.registration;

}

C# FOR JAVA DEVELOPERS

Java C#public Engine Engine { get; set; }

public String Registration { get; private set; }

private Engine engine;private String registration;

public Engine getEngine() {return this.engine;

}

public void setEngine(Engine engine) {this.engine = engine;

}

public String getRegistration() {return this.registration;

}

C# FOR JAVA DEVELOPERS

Java C#using System;

namespace DITest{ public class Engine { public void GoFaster() { Console.WriteLine("VROOM!!"); } }}

import java.lang.*;

package com.stwalkerster.uni.masterclass;

public class Engine {public void goFaster() {

System.out.println("VROOM!!");}

}

DEPENDENCY INJECTION

“"Dependency Injection" is a 25-dollar term for a 5-cent concept.

James Shore - http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html

LET’S LOOK AT AN EXAMPLE…

public class Car{

private Engine engine;

public Car(){

this.engine = new Engine();}

}

• The car makes a new engine when the car is being constructed

DEPENDENCY INJECTION IS GIVING AN OBJECT IT’S DEPENDENCIES.

That’s pretty much all there is to it!

LET’S LOOK AT AN EXAMPLE…

public class Car{

private Engine engine;

public Car(){

this.engine = new Engine();}

}

• We move the creation of the dependency into whatever creates the object in the first place

LET’S LOOK AT AN EXAMPLE…

public class Car{

private Engine engine;

public Car(Engine engine){

this.engine = engine;}

}

• We move the creation of the dependency into whatever creates the object in the first place

• The created engine is now slotted into the car when the car is being constructed

BUT WHY?

• Better separation of code

• Better testability through stubs and mock objects

• The object doesn’t need to know implementation details of it’s dependency.

HIDING THE IMPLEMENTATION DETAILS

public class Car{

private Engine engine;

public Car(Engine engine){

this.engine = engine;}

}

• At the moment, our class depends on an instance of an Engine

• This Engine class is fully functioning

• This could be something like a database connection.

• But what if we wanted to swap this for an ElectricEngine? What about a DieselEngine?

public class ElectricCar{

private ElectricEngine engine;

public ElectricCar(ElectricEngine engine){

this.engine = engine;}

}

public class DieselCar{

private DieselEngine engine;

public DieselCar(DieselEngine engine){

this.engine = engine;}

}

INTERFACES

public class Car{

private IEngine engine;

public Car(IEngine engine){

this.engine = engine;}

}

• Now our class doesn’t care what sort of engine it gets, as long as it looks like and behaves like an engine, it’s good enough.

• As our IEngine interface exposes everything we need to access on the engine, we can continue as normal

INTERFACES

public class Car : ICar{

private IEngine engine;

public Car(IEngine engine){

this.engine = engine;}

}

• Now our class doesn’t care what sort of engine it gets, as long as it looks like and behaves like an engine, it’s good enough.

• As our IEngine interface exposes everything we need to access on the engine, we can continue as normal

UNIT TESTING

public class Car{

public Car(IEngine engine){

this.Engine = engine;}

public IEngine Engine { get; set; }

public void Drive(){

this.Engine.GoFaster();}

}

• If we want to test our Car class, we need an IEngine

• Unit testing is supposed to be of a small unit of code

• We can’t unit test the Drive() method…

… unless we have an engine which has no side effects!

• We use a mock or a stubbed-out implementation of the engine which does nothing.

• We simply pass this mock in with DI

UNIT TESTING

public class Car{

public Car(IEngine engine){

this.Engine = engine;}

public IEngine Engine { get; set; }

public void Drive(){

this.Engine.GoFaster();}

}

[Test]public void TestDriveCar(){

IEngine engine = new MockEngine();

Car myCar = new Car(engine);

// Check the Drive method does the// correct thing…

myCar.Drive()}

A QUICK NOTE…

• Dependencies don’t have to be injected through the constructor.

• It’s acceptable to pass in dependencies through properties or getter/setter methods too

INVERSION OF CONTROL

INVERSION OF CONTROL

public class Application

{

public static void Main(string[] args)

{

IEngine engine = new ElectricEngine();

Car car = new Car(engine);

car.Drive();

}

}

• Dependency Injection removes the need for building dependencies from the class which depends on them

• The problem is just shifted to the caller.

• We need to know the concrete implementation of the Engine at compile time

INVERSION OF CONTROL

public class Application

{

public static void Main(string[] args)

{

IEngine engine = new ElectricEngine();

Car car = new Car(engine);

car.Drive();

}

}

• With Inversion of Control, we delegate the management of the entire lifecycle of the objects to a container.

INVERSION OF CONTROL

• The Inversion of Control framework (or container) is aware of the programmer’s code, and makes calls to it.

• This is the opposite of an API (which the developer calls). Hence “Inversion”

IOC CONTAINERS

• Castle Windsor (.NET)

• Spring (Java)

• Guice ( Java)

• Autofac (.NET)

• Ninject (.NET) Prism (.NET)

• StructureMap (.NET)

THREE CALLS

• The container is used in three different stages

• Bootstrapping

• Resolving

• Disposing

BOOTSTRAPPING

IWindsorContainer container =

new WindsorContainer()

.Install( FromAssembly.This() );

• Set up the IoC container, including:

• Creation of the container

• Configuration of the container

• Register all the components that are needed

RESOLVING

IApplication app =

container.Resolve<IApplication>();

• Get an instance of the root component of the application.

• This should be called as few times as possible – the vast majority of applications will have a single root component.

DISPOSING

container.Dispose();

• Often forgotten

• Shutting down the container will shutdown all the components it manages

• Remember the container manages the entire life cycle of components.

INSTALLERS

public void Install(IWindsorContainer container, IConfigurationStore store)

{container.Register(

Component.For<IEngine>()

.ImplementedBy<Engine>());

}

• Castle Windsor requires the use of an object which extends from IWindsorInstaller to register all of it’s components

• Registration can be split amongst WindsorInstallers

• During the bootstrapping phase, FromAssembly.This() loads all the installers into Castle Windsor

• Registration can be done one component at a time…

INSTALLERS

public void Install(IWindsorContainer container, IConfigurationStore store)

{container.Register(

Classes.FromThisAssembly().InNamespace(“DITest").WithService.AllInterfaces()

);}

• … or by convention.

• Registering by convention is preferred, as there is much less configuration to do.

• Castle also supports registering via XML files, which allows you to swap out classes at runtime, rather than at compile-time.

DEBUGGING

• Clicking “View Detail…” will show more information about what caused an exception

IN THE LAB…

• You will be implementing a basic application to drive a car.

• The car needs an engine, and the application needs the car.

• Use Castle Windsor to create the instances