Inversion of control

  • 158 views
Uploaded on

 

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
158
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
10
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Dependency Injection and Inversion of Control Developing flexible, reusable and testable software Moslem Rashidi
  • 2. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Something about the author • This pattern was introduced in 2004 by Martin Fowler • Martin Fowler is an author and international speaker on software development, specializing in object-oriented  analysis and design, UML, patterns and agile software development. • In March 2000, he became Chief Scientist at ThoughtWorks, a systems integration and consulting company.
  • 3. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Intent Intent of Dependency injection pattern: It refers to the process of supplying an external dependency to a software component
  • 4. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 What is a “Dependency”? Some common dependencies include: • Application Layers – Data Access Layer & Databases – Business Layer • External services & Components – Web Services – Third Party Components • Framework Components – File Objects (File.Delete(…), Directory.Exists(…)) – Web Objects (HttpContext, Session, Request, etc)
  • 5. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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!
  • 6. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 A Concrete Example – A Trade Monitor
  • 7. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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();
  • 8. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Trade Monitor – The Design Refactored (1) • Introduce interface/implementation separation – Logic does not depend on DAO anymore. – Does this really solve the problem? public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor() { limitRepository = new LimitDao(); } public bool TryTrade(string symbol, int amount) { . . . } } public interface ILimitRepository { int GetExposure(string symbol); int GetLimit(string symbol); } limitRepository = new LimitDao(); • The constructor still has a static dependency on DAO
  • 9. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Trade Monitor – The Design Refactored (2) • Introduce Factory • TradeMonitor decoupled from LimitDao 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 TradeMonitor <<interface>> LimitRepository LimitDao <<creates>> return new LimitDao(); • LimitDao still tightly-coupled albeit to Factory
  • 10. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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) { . . . } }
  • 11. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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?
  • 12. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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;} } } • The dependencies are injected from the outside • Components are passive and are not concerned with locating or creating dependencies This is Setter Dependency Injection
  • 13. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Another Idea • Why not just use the constructor? public class TradeMonitor { private ILimitRepository limitRepository; public TradeMonitor(ILimitRepository limitRepository) { this.limitRepository = limitRepository; } } • 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 This is Constructor Dependency Injection
  • 14. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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.
  • 15. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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
  • 16. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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.
  • 17. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 IoC Containers and Features Container Setter DI Ctor DI External config Code config Auto- wiring Lifecycle support` Url System.ComponentModel a a Part of .Net framework PicoContainer.Net a a a a a http://picocontainer.org Windsor a a a ? a http://www.castleproject.org StructureMap a a a P a http://sourceforge.net/projects/structuremap Spring.Net a a a ? a a http://www.springframework.net/ ObjectBuilder a a a a ?? a http://msdn.microsoft.com ?? = More investigation ? = Setter based DI required for primitive dependencies P = Partial still requires configuration to point to assemblies to scan
  • 18. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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); } }
  • 19. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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>
  • 20. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 The Solution – Complex Configuration • What if components take parameters? public class LimitDao { public LimitDao(string connectionString) {…} } public class TradeMonitor { public TradeMonitor(string[] monitoredSymbols) {…} } <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> . . . <configuration> <components> <component id='tradeMonitor' type='AAABank.TradeMonitor, AAABank'> <monitoredSymbols> <array> <elem>MSFT</elem> <elem>TWUK</elem> </array> </monitoredSymbols> . . .
  • 21. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Many other possibilities • Container creates objects – but what objects? • Can return proxy – no need for MarshalByRef inheritance. • Object instance caching. • Aspect Oriented Programming (concerns ,advice ,join point, pointcut). • Remoting by configuration. • Automatic Web Service creation. • . . .
  • 22. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 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
  • 23. Amirkabir University of Technology (Tehran Polytechnic)- Fall 2011 Questions?