260 likes | 439 Views
The Problem with Software? (why it rots). Couplingi.e. dependencies between classesThese are examples of coupling:fred = new Student();TIGHT couplingpublic class Student extends Person {?TIGHT couplingfred = new Person(); A BIT LOOSERpersonFactory = new PersonFactory();MODERATE Fred
E N D
1. Dependency Injection (DI) Or “Inversion of Control”
Dave Elliman
2. The Problem with Software… (why it rots) Coupling
i.e. dependencies between classes
These are examples of coupling:
fred = new Student(); TIGHT coupling
public class Student extends Person {… TIGHT coupling
fred = new Person(); A BIT LOOSER
personFactory = new PersonFactory(); MODERATE
Fred = personFactory.createPerson(); might use Context
Most Java APIs use an abstract factory like this
Can we do better?
3. Yes we can!
4. Where do we create the objects and decide which to pass as arguments? This can be done in a container
Specified in XML (or using annotations)
Can be decided at run time
We have a model like:
Choose objects and create them
Wire up constructor calls
Run program
This is now very loosely coupled
Calling objects only need to know that an object passed can respond to a known method call
Can replace objects with stubs, test objects, mock objects etc.
5. Background Laws SRP – Single Responsibility Principle
A class should have one and only one reason to change
OCP – The Open-Closed Principle
Code should be open to extension and closed to modification
DI is a great help in doing what seems paradoxical at first sight
6. The Law of Demeter Only talk to your friends….
Not to friends of friends
This also limits coupling
a.getX().getY() is a violation
So is… serviceLocator.getService()
7. This needs a bit of explaining
8. PCTIP: Prefer Composition to Inheritance Principle Why?
Because it is a looser form of coupling
9. Design patterns are neat designs based on these principles
10. What is Dependency Injection? DI is all about wiring up objects or plumbing if you prefer
It is about ensuring loose coupling and fits well with design patterns
Design to an interface and then inject the actual class at run time
This is what inheritance is really for in Java, C# and C++
You don’t even need to use inheritance in dynamic languages such as Python, Ruby, Groovy, Objective-C etc.
11. Martin Fowler Martin Fowler has been hugely influential in popularising this design pattern
http://martinfowler.com/
The best description of the material in this lecture is here:
http://martinfowler.com/articles/injection.html
Rod Johnson is the other guru - the man behind Spring
http://www.springsource.com/about/management
12. An EXAMPLE Imagine you have a webapp that tracks the prices of stocks over time. The application is nicely partitioned into different modules that each handle a portion of the job. A StockQuotes module talks to a remote web service to pull down the current values of the stocks you are tracking. A Database module records the stock values over time. Because this data is highly competitive, you require a login to use the system and thus have an Authentication module to handle validation of user names and password. In addition to these "main" modules, there are a number of additional utility modules used by multiple modules: ErrorHandler to standardize the handling and reporting of error messages and Logger to provide a standard way of logging messsages. Imagine you have a webapp that tracks the prices of stocks over time. The application is nicely partitioned into different modules that each handle a portion of the job. A StockQuotes module talks to a remote web service to pull down the current values of the stocks you are tracking. A Database module records the stock values over time. Because this data is highly competitive, you require a login to use the system and thus have an Authentication module to handle validation of user names and password. In addition to these "main" modules, there are a number of additional utility modules used by multiple modules: ErrorHandler to standardize the handling and reporting of error messages and Logger to provide a standard way of logging messsages.
13. Remember the old way public class WebApp
{
public WebApp()
{
quotes = new StockQuotes();
authenticator = new Authenticator();
database = new Database();
logger = new Logger();
errorHandler = new ErrorHandler();
}
// More code here...
}
14. What about the child objects? How does the StockQuotes find the Logger?
How does the Authenticator find the database?
Suppose you want to use a TestingLogger instead? Or a MockDatabase?
15. Service Locator Interface public interface ILocator
{
TObject Get<TObject>();
}
16. Service Locator Example public class MyLocator : ILocator
{
protected Dictionary<Type, object> dict = new Dictionary<Type,object>();
public MyLocator()
{
dict.Add(typeof(ILogger), new Logger());
dict.Add(typeof(IErrorHandler), new ErrorHandler(this));
dict.Add(typeof(IQuotes), new StockQuotes(this));
dict.Add(typeof(IDatabase), new Database(this));
dict.Add(typeof(IAuthenticator), new Authenticator(this));
dict.Add(typeof(WebApp), new WebApp(this));
}
}
17. StockQuotes with Locator public class StockQuotes
{
public StockQuotes(ILocator locator)
{
errorHandler = locator.Get<IErrorHandler>();
logger = locator.Get<ILogger>();
}
// More code here...
}
18. Good things Classes are decoupled from explicit imlementation types
Easy to externalise the configuration
19. Dependency Injection Containers Gets rid of the dependency on the ILocator
Object is no longer responsible for finding its dependencies
The container does it for you
20. Then what? Write your objects the way you want
Setup the container
Ask the container for objects
The container creates objects for you and configures dependencies
21. Setting Up the Container (XML) <DIContainer>
<TypeMap from=“ILogger” to=“Logger” />
<TypeMap from=“IDatabase” to=“Database” />
<TypeMap from=“IErrorHandler” to=“ErrorHandler” />
<TypeMap from=“IQuotes” to=“StockQuotes” />
<TypeMap from=“IAuthenticator” to=“Authenticator” />
</DIContainer>
22. Java/Groovy
Pico Container
Spring Framework
Guice (Google)
HiveMind
Ruby
Rico
Copland DI Frameworks
23. Things are usually easier in Groovy, Python or Ruby This is Strappy - Register a new class
24. Create an instance of a registered class
25. Inject dependencies
26. Using the autowired components