If you want to see the entire course or itself by details, please feel free to go on pluralsight.com
Some vocabulary:
Dependency Inversion Principle (DIP) - Principle used in software architecture saying you would invert the way how the objects are constructed.
Inversion Of Control (IoC) - Is a pattern to implement the Dependency Inversion Principle and it is used also for other principles. But it is how to invert interfaces, flow and dependencies.
Dependency Injection (DI) - Is an implementation of a specific inversion of control pattern.
Inversion of Control Container - The framework to be used.
Dependency Inversion
| We just moved the interface above the line. So, the interface now is defined by upper layer. The main concept is the low level class should conform with the interface. Comparing with the previous implementation, we could have many implementation of that interface, but high level class will not care. |
According to Bob Martin (which defined this concept) there are some assumptions:
a. High level modules should not depend by low level modules. Both of them should depend by abstractions.
b. Abstractions should not depend upon details. Details should depend upon abstractions. With other words, the interfaces should be enough general to keep all information to implement one.
An interface should be defined externally and both high and low classes to depend of them.
Layering of an application
If an application was initially developed as following layers: Policy -> Mechanism -> Utility, a change in layer Utility might affect changes in Mechanism and in Policy. What Bob Martin promoted is: Policy -> Mechanism Interface -> Mechanism interface (implementation ) -> Utility Interface -> Utility interface (implementation).
Inversion of Control
Many different ideas. But basically is a pattern to apply the principle of dependency injection. It is a very broad concept.
Long story short:
| Dependecy Inversion is a principle: classes to depend by abstractions. The Dependency Inversion is a principle implemented through a pattern: Inversion of Control. It has 3 flavours: 1. Interface inversion; 2. Flow inversion; 3. Dependency Creation (Binding inversion). - There are many ways to do that. One of them is called Dependency Injection. That represents the implementation of the pattern of the principle. |
Interface inversion
| Instead to have an implementation for each provider, the consumer will have a single implementation through an abstraction (in this case an interface). In interface inversion, the interface should be implemented by Provider and not by consumer. |
Flow inversion
It is a simple idea to invert the flow. So, if the application is telling you as user what to do, the flow inversion means to tell you to the application what to do. And that is usually happening via graphic user interfaces.
Dependency Creation / Binding Inversion
If you create the object inside the class that is using it, then this is not dependency injection.
Inverting the object creation means to create the classes outside of the class where they are used.
There are many types of Creation Inversion:
1. Factory Pattern
Button button = ButtonFactory.CreateButton();
2. Service Locator
Button button = ServiceLocator.Create (IButton.Class);
3. Dependency Injection
Button button = GetTheRightButton();
OurScreen ourScreen = new OurScreen (button);
4. More...
What is: Is a type of Inversion of Control that move the creation and binding of a dependency outside of the class that depends on it.
So, in a way or other, if we have:
In this way, the situation becomes:It is a simple idea to invert the flow. So, if the application is telling you as user what to do, the flow inversion means to tell you to the application what to do. And that is usually happening via graphic user interfaces.
Dependency Creation / Binding Inversion
If you create the object inside the class that is using it, then this is not dependency injection.
Inverting the object creation means to create the classes outside of the class where they are used.
There are many types of Creation Inversion:
1. Factory Pattern
Button button = ButtonFactory.CreateButton();
2. Service Locator
Button button = ServiceLocator.Create (IButton.Class);
3. Dependency Injection
Button button = GetTheRightButton();
OurScreen ourScreen = new OurScreen (button);
4. More...
What is: Is a type of Inversion of Control that move the creation and binding of a dependency outside of the class that depends on it.
So, in a way or other, if we have:
| So, an idea is to use another class known as Injector that is acting as an Injector. The injector knows about my class, my dependency, interfaces. It is the injector responsibility to bind those things together. So, when you are using dependency injector you should have something that is doing the injection. Also, that injector is important for all classes in the same situation. |
a) Constructor Injection
- the most common and simple: it passes the dependency in the constructor of the dependent classes
| In this way, on constructor, the ICreditCard object is passed in. And also it will be kept in that class as a dependency. The good think is you are not able to create a class without dependencies. |
- Use setter instead of constructor. The down side is you could create a class without specifying all required setters (dependencies).
- It allows us to create and use a class even without dependencies. It gives us flexibility. But in the same way it creates also danger to use a class without knowing if the dependency was set.
- The example for using a setter injection:
- Dependent class will implement an interface
- Injector uses the interface to inject the dependency.
- It is a little bit uncommon.
Warnings related to Dependency Injection
1. Leaks the internal implementation details of a class.
- It violates encapsulation: because it takes the internal implementation and exposes it through constructor of the class.
2. Prevent deferred creation
- If the idea of creating an object until needed, cannot be applied here.
- Theoretically is not possible, because when you pass a dependency to the class, you need to create it first. The passing itself is a usage of that dependency.
- Sometimes it is possible to do this with some kind of lazy generation, but in general not.
- You should be very careful to the large data graphs.
3. Numbs you from the pain
- Too many dependencies might be created.
- Unit tests are easier.
Building an IoC Container
What is: - It is just a framework to do the dependency injection. This is the basic.
- Also it should configure dependencies (give me a concrete type instead of another one)
- Automatically resolves the configured dependencies.
So, when you ask for a particular object, it knows by interface or by type what concrete type is, and it goes down that chain and init that object with its references.
Only IoC Container will know about those objects. The objects will never know about IoC Container. This is the key difference between an IoC Container and a Service Locator.
In the following figure will be shown an example of IoC container in the shopper example:
So, in other words, the shopper class requests a dependency which implements ICreditCard in constructor. There are 2 classes which are implementing ICreditCard: MasterCard and Visa. So, depending how IoC Container is configured, it will serve one of: MasterCard or Visa.
Using Unity
Unity in an IoC container from Microsoft. It is part of Enterprise Library. Can be taken also as nuget package. And it is extendable.
Setting up Unity
You could do this via NuGet.
Registering types
You need to create an unity container and register types (optional)
- What is specific to Unity is that you don't need to register every dependency with Unity.
- But if many classes implement an interface and we are asking for that interface, then we need to register, to let unity to give us what we need.
- The basic scenario:
var container = new UnityContainer();
container.RegisterType<ICreditCard, MasterCard>();
- If:
- you want to register a type and when you will get it back you want to get it with a value:
container.RegisterType<ICreditCard, MasterCard>( new InjectionProperty ("ChargeCount", 5));
- you want to register a type with a name:
container.RegisterType<ICreditCard, MasterCard> ("DefaultCard");
container.RegisterType<ICreditCard, Visa>("BackupCard");
- you want to register an Instance and get it back:
var object = new object();
container.RegisterInstance
Using container
- In order to use, your usually command is Resolve:
var shopper = container.Resolve<Shopper>();
Controlling lifetime of an object
- With an IoC you could choose between having a singleton or an instance.
- The default is to create an instance every time when the container resolves a request.
- For a singleton:
container.RegisterType<ICreditCard, MasterCard>(new ContainerControlledLifeTime());















