Dependency injection and inversion of control
This presentation is the property of its rightful owner.
Sponsored Links
1 / 19

Dependency Injection and Inversion of Control PowerPoint PPT Presentation


  • 44 Views
  • Uploaded on
  • Presentation posted in: General

Dependency Injection and Inversion of Control. Developing flexible, reusable and testable software Part 1 Nick Hines March 2006. Loosely Coupled Systems. Good OO Systems – organised as web of interacting objects Goal – High cohesion, low coupling. Advantages of low coupling Extensibility

Download Presentation

Dependency Injection and Inversion of Control

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Dependency injection and inversion of control

Dependency Injection and Inversion of Control

Developing flexible, reusable and testable software

Part 1

Nick Hines

March 2006


Loosely coupled systems

Loosely Coupled Systems

  • Good OO Systems – organised as web of interacting objects

  • Goal – High cohesion, low coupling

  • Advantages of low coupling

    • Extensibility

    • Testability

    • Reusability

  • Not so easy to achieve!


A concrete example a trade monitor

A Concrete Example – A Trade Monitor


Trade monitor the design

Trade Monitor – The design

  • TradeMonitor is coupled to LimitDao – this is not good!

    • Extensibility – what if not database but distributed cache

    • Testability – where do the limits for test come from?

    • Reusability – logic is fairly generic . . .

public class TradeMonitor

{

private LimitDao limitDao;

public TradeMonitor()

{

limitDao = new LimitDao();

}

public bool TryTrade(string symbol, int amount)

{

int limit = limitDao.GetLimit(symbol);

int exposure = limitDao.GetExposure(symbol);

return (exposure + amount > limit) ? false : true;

}

}

public class LimitDao

{

public int GetExposure(string symbol)

{

// Do something with the database

}

public int GetLimit(string sysmbol)

{

// Do something with the database

}

}

limitDao = new LimitDao();


Trade monitor the design refactored 1

Trade Monitor – The Design Refactored (1)

  • Introduce interface/implementation separation

    • Logic does not depend on DAO anymore.

    • Does this really solve the problem?

  • The constructor still has a static dependency on DAO

public interface ILimitRepository

{

int GetExposure(string symbol);

int GetLimit(string symbol);

}

public class TradeMonitor

{

private ILimitRepository limitRepository;

public TradeMonitor()

{

limitRepository = new LimitDao();

}

public bool TryTrade(string symbol, int amount)

{

. . .

}

}

limitRepository = new LimitDao();


Trade monitor the design refactored 2

Trade Monitor – The Design Refactored (2)

  • Introduce Factory

  • TradeMonitor decoupled from LimitDao

  • LimitDao still tightly-coupled albeit to Factory

public class LimitFactory

{

public static ILimitRepository GetLimitRepository()

{

return new LimitDao();

}

}

public class TradeMonitor

{

private ILimitRepository limitRepository;

public TradeMonitor()

{

limitRepository = LimitFactory.GetLimitRepository();

}

public bool TryTrade(string symbol, int amount)

{

. . .

}

}

LimitFactory

return new LimitDao();

<<creates>>

TradeMonitor

LimitDao

<<interface>>

LimitRepository


Trade monitor the design refactored 3

Trade Monitor – The Design Refactored (3)

  • Introduce ServiceLocator

  • This gives us extensibility, testability, reusability

public class ServiceLocator

{

public static void RegisterService(Type type, object impl)

{. . .}

public static object GetService(Type type)

{. . .}

}

public class TradeMonitor

{

private ILimitRepository limitRepository;

public TradeMonitor()

{

object o =

ServiceLocator.GetService(typeof(ILimitRepository));

limitRepository = o as ILimitRepository;

}

public bool TryTrade(string symbol, int amount)

{

. . .

}

}


Servicelocator problems

ServiceLocator - Problems

  • Sequence dependence

  • Cumbersome setup in tests

  • Service depends on infrastructure code, (ServiceLocator)

  • Code needs to handle lookup problems

  • Aren’t these problem minor?

    Why settle for something we know has issues?


A different view

A Different View

  • What about adding a setter and let something else worry about creation and resolution?

public class TradeMonitor

{

private ILimitRepository limitRepository;

public TradeMonitor()

{

}

public ILimitRepository Limits

{

set { limitRepository = value;}

}

}

This is SetterDependency Injection

  • The dependencies are injected from the outside

  • Components are passive and are not concerned with locating or creating dependencies


Another idea

Another Idea

  • Why not just use the constructor?

public class TradeMonitor

{

private ILimitRepository limitRepository;

public TradeMonitor(ILimitRepository limitRepository)

{

this.limitRepository = limitRepository;

}

}

This is ConstructorDependency Injection

  • No setters for dependent components, (obviously)

  • One-shot initialisation – components are always initialised correctly

  • All dependencies are clearly visible from code

  • It is impossible to create cyclic dependencies


What about inversion of control

What about Inversion of Control?

  • Dependency Injection - one example of IoC design principle.

  • Also known as the Hollywood Principle

    • Don’t call us, we’ll call you!

  • Objects rely on their environment to provide dependencies rather than actively obtaining them.

  • Inversion of Control can make the difference between a library and a framework.


Ioc containers

IoC Containers

  • There are still some open questions

    • Who creates the dependencies?

    • What if we need some initialisation code that must be run after dependencies have been set?

    • What happens when we don’t have all the components?

  • IoC Containers solve these issues

    • Have configuration – often external

    • Create objects

    • Ensure all dependencies are satisfied

    • Provide lifecycle support


It gets better

It Gets Better

  • We can use reflection to determine dependencies – no need for config files.

  • Most IoC containers support auto-wiring.

  • Make components known to container.

  • Container examines constructors and determines dependencies.

  • Auto-wiring provides other benefits.

  • Less typing, especially long assembly names.

  • Static type checking by IDE at edit time.

  • More intuitive for developer.


Ioc containers and features

IoC Containers and Features


The solution test case

The Solution – Test Case

[TestFixture]

public class TradeMonitorTest

{

[Test]

public void MonitorBlocksTradesWhenLimitExceeded()

{

DynamicMock mockRepository = new DynamicMock(typeof(ILimitRepository));

mockRepository.SetupResult('GetLimit', 1000000, new Type[] { typeof(string) });

mockRepository.SetupResult('GetExposure', 999999, new Type[] { typeof(string) });

TradeMonitor monitor = new TradeMonitor((ILimitRepository)mockRepository.MockInstance);

Assert.IsFalse(monitor.TryTrade('MSFT', 1000), 'Monitor should block trade');

}

}

public class TradeMonitor

{

private ILimitRepository repository;

public TradeMonitor(ILimitRepository repository){this.repository = repository; }

public bool TryTrade(string symbol, int amount)

{

int limit = repository.GetLimit(symbol);

int exposure = repository.GetExposure(symbol);

return ((amount + exposure) <= limit);

}

}


The solution using the windsor container

The Solution – Using the Windsor Container

  • Code configuration

IWindsorContainer container = new WindsorContainer();

container.AddComponent('limitRepository', typeof(ILimitRepository), typeof(LimitDao));

container.AddComponent('tradeMonitor', typeof(TradeMonitor));

TradeMonitor monitor = (TradeMonitor)container['tradeMonitor'];

monitor.TryTrade('MSFT', 1000);

  • External configuration

IWindsorContainer container = new WindsorContainer('config.xml');

TradeMonitor monitor = (TradeMonitor)container['tradeMonitor'];

monitor.TryTrade('MSFT', 1000);

<configuration>

<components>

<component id='limitRepository' service='AAABank.ILimitRepository, AAABank'

type='AAABank.LimitDao, AAABank' />

<component id='tradeMonitor' type='AAABank.TradeMonitor, AAABank' />

</components>

</configuration>


The solution complex configuration

The Solution – Complex Configuration

  • What if components take parameters?

public class LimitDao

{

public LimitDao(string connectionString) {…}

}

<configuration>

<components>

<component id='limitRepository' service='AAABank.ILimitRepository, AAABank'

type='AAABank.LimitDao, AAABank'>

<connectionString>Data Source=AServer;Initial Catalog=BankDB;User ID=sa</connectionString>

</component>

. . .

public class TradeMonitor

{

public TradeMonitor(string[] monitoredSymbols) {…}

}

<configuration>

<components>

<component id='tradeMonitor' type='AAABank.TradeMonitor, AAABank'>

<monitoredSymbols>

<array>

<elem>MSFT</elem>

<elem>TWUK</elem>

</array>

</monitoredSymbols>

. . .


Many other possibilities

Many other possibilities

  • Container creates objects – but what objects?

  • Can return proxy – no need for MarshalByRef inheritance.

  • Object instance caching.

  • Aspect Oriented Programming.

  • Remoting by configuration.

  • Automatic Web Service creation.

  • . . .


Summary

Summary

  • Container based DI facilitates: -

    • Testability

    • Extensibility

    • Reusability

  • Makes the difference between framework and library

    • Not just use but extend

  • Essential for complex Domain Driven Design

    • Easier to separate 'infrastructure' from business logic


  • Login