DEPENDENCY INJECTION INVERSION OF CONTROL WHATS GOING TO

  • Slides: 35
Download presentation
DEPENDENCY INJECTION & INVERSION OF CONTROL

DEPENDENCY INJECTION & INVERSION OF CONTROL

WHAT’S GOING TO BE COVERED • Quick intro to C# for Java developers •

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#

C# FOR JAVA DEVELOPERS • Most of this lecture is going to use C# • DI is possible with any object-oriented language • Io. C requires a container

C# FOR JAVA DEVELOPERS Java public class Car { private Engine engine; private String

C# FOR JAVA DEVELOPERS Java public class Car { private Engine engine; private String registration; private int window. Count; } public Car() { this. engine = new Engine(); this. registration = "SW 14 ABC"; this. window. Count = 6; } C# public class Car { private Engine engine; private string registration; private int window. Count; } public Car() { this. engine = new Engine(); this. registration = "SW 14 ABC"; this. window. Count = 6; }

C# FOR JAVA DEVELOPERS Java C# private Engine engine; private String registration; private Engine

C# FOR JAVA DEVELOPERS Java C# private Engine engine; private String registration; private Engine engine; private string registration; public Engine get. Engine() { return this. engine; } public Engine { get { return this. engine; } set { this. engine = value; } } public void set. Engine(Engine engine) { this. engine = engine; } public String get. Registration() { return this. registration; } public String Registration { get { return this. registration; }

C# FOR JAVA DEVELOPERS Java private Engine engine; private String registration; public Engine get.

C# FOR JAVA DEVELOPERS Java private Engine engine; private String registration; public Engine get. Engine() { return this. engine; } public void set. Engine(Engine engine) { this. engine = engine; } public String get. Registration() { return this. registration; } C# private string registration; public Engine { get; set; } public String Registration { get { return this. registration; } }

C# FOR JAVA DEVELOPERS Java private Engine engine; private String registration; public Engine get.

C# FOR JAVA DEVELOPERS Java private Engine engine; private String registration; public Engine get. Engine() { return this. engine; } public void set. Engine(Engine engine) { this. engine = engine; } public String get. Registration() { return this. registration; } C# public Engine { get; set; } public String Registration { get; private set; }

C# FOR JAVA DEVELOPERS Java C# import java. lang. *; using System; package com.

C# FOR JAVA DEVELOPERS Java C# import java. lang. *; using System; package com. stwalkerster. uni. masterclass; namespace DITest { public class Engine { public void Go. Faster() { Console. Write. Line("VROOM!!"); } } } public class Engine { public void go. Faster() { System. out. println("VROOM!!"); } }

DEPENDENCY INJECTION

DEPENDENCY INJECTION

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

“ "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

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

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

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

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

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

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 Electric. Engine? What about a Diesel. Engine?

public class Electric. Car { private Electric. Engine engine; } public Electric. Car(Electric. Engine

public class Electric. Car { private Electric. Engine engine; } public Electric. Car(Electric. Engine engine) { this. engine = engine; } public class Diesel. Car { private Diesel. Engine engine; } public Diesel. Car(Diesel. Engine engine) { this. engine = engine; }

INTERFACES public class Car { private IEngine engine; } public Car(IEngine engine) { this.

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)

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;

UNIT TESTING public class Car { public Car(IEngine engine) { this. Engine = engine; } public IEngine { get; set; } } public void Drive() { this. Engine. Go. Faster(); } • 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;

UNIT TESTING public class Car { public Car(IEngine engine) { this. Engine = engine; } [Test] public void Test. Drive. Car() { IEngine engine = new Mock. Engine(); Car my. Car = new Car(engine); public IEngine { get; set; } } public void Drive() { this. Engine. Go. Faster(); } // Check the Drive method does the // correct thing… } my. Car. Drive()

A QUICK NOTE… • Dependencies don’t have to be injected through the constructor. •

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

INVERSION OF CONTROL public class Application { public static void Main(string[] args) { IEngine

INVERSION OF CONTROL public class Application { public static void Main(string[] args) { IEngine engine = new Electric. Engine(); 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

INVERSION OF CONTROL public class Application { public static void Main(string[] args) { IEngine engine = new Electric. Engine(); 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

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)

IOC CONTAINERS • Castle Windsor (. NET) • Spring (Java) • Guice ( Java) • Autofac (. NET) • Ninject (. NET) Prism (. NET) • Structure. Map (. NET)

THREE CALLS • The container is used in three different stages • Bootstrapping •

THREE CALLS • The container is used in three different stages • Bootstrapping • Resolving • Disposing

BOOTSTRAPPING IWindsor. Container container = new Windsor. Container(). Install( From. Assembly. This() ); •

BOOTSTRAPPING IWindsor. Container container = new Windsor. Container(). Install( From. Assembly. This() ); • Set up the Io. C container, including: • Creation of the container • Configuration of the container • Register all the components that are needed

RESOLVING • Get an instance of the root component of the application. IApplication app

RESOLVING • Get an instance of the root component of the application. IApplication app = container. Resolve<IApplication>(); • This should be called as few times as possible – the vast majority of applications will have a single root component.

DISPOSING • Often forgotten container. Dispose(); • Shutting down the container will shutdown all

DISPOSING • Often forgotten container. Dispose(); • 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( IWindsor. Container container, IConfiguration. Store store) { container. Register( Component.

INSTALLERS public void Install( IWindsor. Container container, IConfiguration. Store store) { container. Register( Component. For<IEngine>(). Implemented. By<Engine>() ); } • Castle Windsor requires the use of an object which extends from IWindsor. Installer to register all of it’s components • Registration can be split amongst Windsor. Installers • During the bootstrapping phase, From. Assembly. This() loads all the installers into Castle Windsor • Registration can be done component at a time…

INSTALLERS public void Install( IWindsor. Container container, IConfiguration. Store store ) { container. Register(

INSTALLERS public void Install( IWindsor. Container container, IConfiguration. Store store ) { container. Register( } ); Classes. From. This. Assembly(). In. Namespace(“DITest"). With. Service. All. Interfaces() • … 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

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

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