This document discusses dependency injection and inversion of control principles. It provides examples of how to implement dependency injection using interfaces, factories, and the Google Guice framework. The key points are:
1) Dependency injection loosens coupling between classes by allowing dependencies to be injected externally rather than created internally. This improves testability and flexibility.
2) Google Guice is an inversion of control framework that uses annotations and bindings to configure dependency injection. It handles object instantiation and wiring of dependencies.
3) With Guice, classes declare dependencies through interfaces or annotations rather than directly instantiating dependencies. This decouples classes and allows dependencies to vary without code changes.
2. Why are we doing this ??
● To learn a new buzz word ??
● To improve code quality ??
● Is this all ??
3.
4. Problem
We have a simple problem which we need to solve
Let say we have a class, Person, and this class needs
to send a message (Say email).
The Person class requires the aid of some other
class, Email, in order to send a message.
14. Inversion of Control
● Invert the controls to achieve loose coupling
● The control means any additional responsibilities a class has other than its main responsibility,
such as control over the flow of an application, control over the flow of an object creation or
dependent object creation and binding. (Don't forget SRP)
● Analogy of Car
● If you want to do TDD then you must use IoC principle without which TDD is not possible.
15. Don't call us, we'll call you
● Software frameworks, callbacks, schedulers, event loops, dependency injection are examples of
design patterns that follow the inversion of control principle
● Helps in
○ To focus a module on the task it is designed for.
○ To free modules from assumptions about how other systems do what they do and
instead rely on contracts.
○ To prevent side effects when replacing a module.
18. Dependency Inversion Principle
● Dependency inversion principle refers to a specific form of decoupling software modules.
● High-level modules should not depend on low-level modules. Both should depend on
abstraction.
● Abstractions should not depend on details. Details should depend on abstractions.
20. CustomerBusinessLogic and CustomerDataAccess classes
are loosely coupled classes because
CustomerBusinessLogic does not depend on concrete
DataAccess class, instead it includes reference of
ICustomerDataAccess interface. So now, we can easily
use another class which implements
ICustomerDataAccess with different implementation.
24. ● The problem with the solution is that we used DataAccessFactory inside
CustomerBusinessLogic class. So, suppose there is another implementation of
ICustomerDataAccess for some reason and we want to use that new class inside
CustomerBusinessLogic. Then, we need to change the source code of CustomerBusinessLogic
class also. (Violation of Open Closed Principle)
● All the dependencies must be provided externally.
● Can be done via factories
● Can be done via IoC Containers say Google Guice.
Dependency Injection
25.
26. Google Guice to the rescue
● Guice’s job is to assemble graphs of objects. You request an instance of a given type, and it
figures out what to build, resolves dependencies, and wires everything together.
● Guice alleviates the need for factories and the use of new in your Java code. Think of Guice's
@Inject as the new new.
● Code will be easier to change, unit test and reuse in other contexts.
27. Guice Bindings - Linked Binding
● Linked bindings map a type to its implementation.
● This example maps the interface TransactionLog to the implementation
DatabaseTransactionLog
28. ● Chaining of Bindings can also be done.
● In this case, when a TransactionLog is requested, the injector will return a
MySqlDatabaseTransactionLog.
29. Binding Annotations
● What if you want to bind different implementations of interfaces in different contexts ??
● For example, you might want both a PayPal credit card processor and a Google Checkout
processor to be bound to CreditCardProcessor Interface ?
32. Instance Binding
You can bind a type to a specific instance of that type. This is usually only useful only for objects that
don't have dependencies of their own, such as value objects:
33. Provides Binding
● When you need code to create an object, use an @Provides method.
● The method must be defined within a module, and it must have an @Provides annotation.
● Whenever the injector needs an instance of that type, it will invoke the method.
● Guice does not allow exceptions to be thrown from Providers. Exceptions thrown by @Provides
methods will be wrapped in a ProvisionException. It is bad practice to allow any kind of
exception to be thrown -- runtime or checked -- from an @Provides method.
34. Untargeted Bindings
● You may create bindings without specifying a target. This is most useful for concrete classes
● When specifying binding annotations, you must still add the target binding, even it is the same
concrete class
35. Just In Time Binding
● The bindings in a modules are called explicit bindings, and the injector uses them whenever
they're available.
● If a type is needed but there isn't an explicit binding, the injector will attempt to create a Just-In-
Time binding.
36. @ImplementedBy
● Annotate types tell the injector what their default implementation type is.
● The @ImplementedBy annotation acts like a linked binding, specifying the subtype to use when
building a type.