Contents
Introduction
Welcome to my post. Here, I will try to describe DIP, IoC, DI and IoC container. Most of the time, beginner developers face problems with DIP, IoC, DI and IoC Container. They mix-up all together and find it difficult to identify the difference between them and don’t know why they need to use them. On the other hand, lots of people use DI, IoC without knowing it and what problem it solves. There are many posts, articles, blogs available on this topic but not all together. Here, I have tried to describe all together. I hope after reading my post, the reader will be able to identify the difference between DIP, IoC, DI & IoC Container/framework, also know how and when to use them. I also hope after reading my post, readers will able to create their own IoC container. Before going into details, let me describe DIP, IoC, DI and IoC container using simple sentences.
Dependency Inversion Principle (DIP) | Principle used in architecting software |
Inversion of Control (IoC) | Pattern used to invert flow, dependencies and interfaces |
Dependency Injection (DI) | Implementation of IoC to invert dependencies |
IoC Container | Framework to do dependency injection. It helps to map dependencies, manage object creation & lifetime. |
Background
DIP is a software design principle and IoC is a Software design pattern. Let's see what is Software design principle and pattern.
- Software design principle: Principle provides us guideline. Principle says what is right and what is wrong. It doesn’t tell us how to solve a problem. It just gives some guidelines so that we can design good software and avoid bad design. Some principles are DRY, OCP, DIP, etc.
- Software design pattern: Pattern is a general reusable solution to a commonly occurring problem within a given context in software design. Some patterns are factory pattern, Decorator pattern, etc.
Now we have everything for going into details.
So principle defines good and bad. So we can say if we maintain principle during software design, then it will be good design. If we don’t maintain principle, then we may fall into problems. Now we are only focusing on Dependency Inversion Principle (DIP) which is D on SOLID principle.
Dependency Inversion Principle (DIP)
Instead of lower level modules defining an interface that higher level modules depend on, higher level modules define an interface that lower level modules implement.
Let's Try to Understand DIP with Some Example
Let try to describe the above principle with simple example of portable charger or devices. Consider you have Camera, Phone and other devices. These devices use cable to connect with computer or charger. A simple jack or port is used to connect with computer or charger, right? Now if you are asked who has defined the port or jack; cable or your device?
You definitely answer device. Based on device port varies. So from the story, what we found is that port doesn’t define what will be the device but device defines what will be port or jack.
So software modules are similar. High level module defines the interface and low level module implements that interface and low level module doesn’t define interface like jack doesn’t define the device.
Let's again consider the DIP according to Bob Martin's definition:
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
So from the principle, we can say high level module should not depend on low level module. Both depend on abstraction. Abstraction should not depend on low level.
Let's Try to Understand DIP with Some Example
Case 1: Dependency not inverted (High level module depends on low level interface)
From the figure, we found high level depends on low level interface. So high level class needs to think about all the interfaces. When new low level class comes, then again high level class needs to change which makes complexity on maintenance and it violates open close principle.
Case 2: Dependency Inversion
Now see the figure. Here, higher level class defines the interface and higher level class doesn’t depend on lower level class directly. Lower level classes implements interface defined by higher level class so higher level class doesn’t need to change when new implementation arrived.
Case 3: A Copy program without DIP
Consider the above example:
- First, ignore dotted objects. You have a copy program which is responsible for taking input from keyboard and writing to text file. Your current copy program can maintain both of them so it doesn’t makes problem.
- Now consider after a certain period, your boss asked you to develop your copy program so that it can store reading data to database. Then what will you do. You will again change to copy program so that it can write to database. This will increase the complexity of your program.
Case 4: Copy Program with DIP
If we consider the above example, then we find that the copy program is dependent on reader interface and writer interface defined by copy program. So it is directly not dependent on lower level classes like read from scanner, write to printer, etc. As a result, we don’t need to change the copy program when a new requirement will come and our copy program is independent.
I think DIP is little bit clear. Now let’s see what will be the benefit for maintaining DIP and problems for not maintaining DIP. If we don’t maintain software design principle, then our software design will be bad design. Now consider a software design where we didn’t maintain Dependency Inversion Principle (DIP). As we are not maintaining DIP, then we will have a problem. Let's see.
Problems We Will Face if We Do Not Maintain DIP
- System will be rigid: It will be difficult to change a part of the system without affecting too many other parts of the system.
- System will be fragile: When we will make a change, unexpected parts of the system will break.
- System or component will be immobile: It will be difficult to reuse it in another application because it cannot be disentangled from the current application. And so on…
Benefit of Maintaining DIP
First thing is we can solve the above problems. That means our system will be loosely coupled, independent, modular, testable and so on. As DIP is a principle, it does not say how to solve the problem. If we want to know how to solve the problem, then we have to move on to Inversion of Control.
Inversion of Control (IoC)
DIP doesn’t tell us how to solve the problem but Inversion of Control defines some way so that we can maintain DIP. It is the thing which you can practically apply on your software development. Lots of definition available for IoC. Here I just try to give a simple definition so that we can easily understand.
What is IoC
IoC helps us to apply DIP. In simple IoC is Inverting the control of something by switching who control. Particular class or another module of the system will be responsible for creation object from outside. Inversion of control means we are changing the control from the normal way.
IoC and DIP
DIP says High level module should not depend on low level module and both should depend on abstraction. IoC is a way that provides abstraction. A way to change the control. IoC gives some ways to implement DIP. If you want to make independent higher level module from the lower level module, then you have to invert the control so that low level module is not controlling interface and creation of the object. Finally, IoC gives some way to invert the control.
Splitting IoC
We can split IoC in the following ways. (Description will be provided later.)
- Interface Inversion: Inverting interfaces
- Flow inversion: Invert the flow of control and it is the foundation idea of IoC which is similar to, "Don’t call us, we will call you."
- Creation Inversion: This is mostly used by developers. We will use it when we go to DI and IoC container.
Fitting Altogether (DIP, IoC and DI)
I am not making full curry here. Just consider the above image how everything together fits. This is the view how all things fit together. DI is not only the way of Dependency creation that’s why I have used “….” . There are many ways to implement Dependency creation. Here, I am just interested in DI. That’s why I have shown it in the figure and others are doted. At the top is DIP which is a way of designing software. It doesn’t sys how to make independent module. IoC provides some way of applying DPI principle. IoC doesn’t provide specific implementation. It gives some methods so that we can invert the control. If we want to invert control using Binding inversion or dependency creation, then we can achieve it by implementing dependency injection (DI).
Interface Inversion
Interface inversion is the inversion of interface. Consider a Reader application. This reader application is read from text file.
Now consider this application also read from pdf and word file:
Creating too many interface doesn’t mean I am implementing IoC or maintaining DPI. What is the benefit of using too many interfaces? Here we have no benefit because every time we have to change our reader class and reader class had to maintain all the interfaces. So ultimately we are not benefited. Now we have a method called interface inversion. Let invert the interfaces.
By considering the above example, we remove all the interfaces from lower level classes and make single interface defined by reader class. What we did here just invert the interface. Now we have lots of benefit. We don’t need to change reader class anymore and reader class is independent. Now consider above thing as a provider model.
Flow Inversion
Let’s see something about flow inversion. Flow inversion is the simple inversion which is backbone of the IoC. If you think about normal flow then you will find it is procedural.
Normal Flow
Figure: Command line program
Consider a command line program which first asks for your name then you put your name, again it will ask for your age then you will provide your age. What is going on here? You found your command line application executes one by one that means basic flow is procedural. It goes step by step.
Inverted Flow
Now let’s try to invert the flow. Now we can think about a GUI. Consider our GUI consists of two input box one for user name and another for user age. Just consider the following figure:
Figure: GUI Program
Now you see you can provide your name and your age without maintaining flow. If you want you can put your age first and your name last. So you don’t need to depend on basic flow. On the other hand when you press save button, then your program saves information. In command line program you are asking for first do this, then do this but in GUI flow is controlled by user.
Creation Inversion
This is most familiar inversion of control method and we are going to use it on IoC container. Now consider the following.
In a normal way, how can we create an object:
Class A
{
YourClass yourObject = new YourClass();
}
So you are creating object which is dependent on another class and makes system tightly coupled. Here you are creating the object from inside your current class.
Now consider Interface Inversion:
Class A
{
IYourInterface yourObject = new YourClass();
}
Even we are using interface inversion still we creating object inside the class. So creation of the object still has dependences. So what is creation inversion? What things we have to do to break the dependences? Let's see...
Inverting Control/ Creation Inversion
Creating object outside of the class they are being used in. We are making object from outside of the class so higher level class is not directly depending on lower level class. Now let’s see why we need to invert the control.
Consider you have a GUI and you want to place a button on a screen. Your button has many design so your UI shows button based on UserSettings. Now what will be our code if we are doing in a normal way. Let's see.
Button btn;
switch (UserSettings.ButtonStyle)
{
case "Metro": btn = new MetroButton();
break;
case "Office2010": btn = new Office2007Button();
break;
case "Fancy": btn = new FancyButton();
break;
}
So from the code, our UI will show different style button based on user settings. Now after a certain period, new styles come, then again you have to change UI code. If 20 style comes, then we have to change 20 times. As Creation inversion says, we have to create object outside of the class. Now let's try to follow that.
Now consider we have a FactoryClass
(we can learn more by reading factory pattern) which is responsible for providing button object based on user settings. This factory class is responsible for object creation. Now again, let’s see our UI class after implementing ButtonFactory
class. Here, I am not describing how to create Button
factory class, but you will find details later.
So new UI has the following code:
Button btn = ButtonFactory.CreateButton();
So our button is depending on factory class and we don’t need to change our UI code when a new style comes. Here, object creation is done from outside of the UI class. In this way, we are inverting the creation of object.
Types of Creation Inversion
Factory Pattern
If you check the above example, then you will find that I have managed the creation of object from outside of the UI class. In factory pattern, we do something like:
Button btn = ButtonFactory.CreateButton();
Service Locator
Button btn = ServiceLocator.Create(IButtonControl);
In service locator pattern, we are passing interface and corresponding implementation of requested interface will be provided by service locator. Here, I am not describing details because I am only focused on describing Dependency Injection (DI).
Dependency Injection (DI)
In dependency injection, we pass dependency. Consider the following simple code:
Button btn = GetButtonInstanceBasedOnUserSettings();
OurUi ourUI = new OurUi(btn);
Here, we passed the dependencies when creating UI. In DI, the key idea is passing dependencies. DI is not only constructor injection. In the next section, I will describe more details on DI.
More…
There are more way to creation inversion.
So in summary, any time you are taking the dependencies and binding the dependencies out of the class, you are inverting the control and this is treated as Inversion of Control (IoC).
Dependency Injection (DI)
Most of the time, people mix-up DI with IoC. IoC describes different ways of inverting the control. On the other hand, DI inverts the Control by passing dependencies. So here, I will try to describe the following things:
- What is Dependency Injection (DI)
- Types of DI
- Constructor Injection
- Setter Injection
- Interface Injection
What is Dependency Injection
A type of IoC where we move the creation and binding of dependency outside of the class that depends on it. Normally, objects are created inside of the dependent class and bounded inside the dependent class. In DI, it is done from outside of the dependent class. Let us consider an example:
Figure: Tiffin box with breakfast
Suppose you bring a Tiffin box to your office for breakfast. So you bring everything that you needed to breakfast. So you are managing the breakfast by Tiffin box. This is similar to creation object inside of the class in a sense you are managing what you needed.
Figure: Your breakfast will be provided like the above image
Now consider another example. In your office, breakfast will be provided. You don’t need to bring the Tiffin box with you. Then what will happen. Still you can have breakfast but now it is provided by the office. This is similar to DI where the required object is provided outside of the class.
Types of Dependency Injection
Constructor Injection
This is the most common form DI. Pass dependencies to dependent class through constructor. An injector creates the dependencies and passes the dependencies through constructor. Let's consider the following example. We have a PurchaseBl
class which is responsible for performing save operation and depends on IRepository
.
public class PurchaseBl
{
private readonly IRepository _repository;
public PurchaseBl(IRepository repository)
{
_repository = repository;
}
public string SavePurchaseOrder()
{
return _repository.Save();
}
}
Now let's see how we will access this PurchaseBl
and how we will pass dependency through constructor:
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl(dbRepository);
From the above example, we see PurchaseBl
depends on IRepository
and the PurchaseBl
doesn’t directly create any instance of repository. This repository will be provided outside of the class. As a result, our PurchaseBl
is independent from lower level class and it provides loose coupling.
Here, Repository
class implements IRepository
which saves information to database. Now think if you need to save information to TextFile
, then you don’t need to change the PurchaseBL
class. You just have to pass another TextRepository
class which is responsible for saving data to text file. Now let me show you if you have TextRepository
class, then how you will pass that repository.
IRepository textRepository = new TextRepository();
PurchaseBl purchaseBl = new PurchaseBl(textRepository);
So you can change dependencies without affecting higher level class PurchaseBl
.
Setter Injection
This is another type of DI technique where we pass dependencies through setter instead of constructor. So what do we have to do to setter injection:
Create setter in dependent class: In C#, you just need to create a property. Use that property to set dependencies.
Pass dependences through setter: Here, we can pass dependences through setter. We also create an object of class without passing dependences.
Let us see how I can create setter injection:
public class PurchaseBl
{
public IRepository Repository { get; set; }
public string SavePurchaseOrder()
{
return Repository.Save();
}
}
Now let’s inject dependency through setter.
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl();
purchaseBl.Repository = dbRepository;
Console.WriteLine(purchaseBl.SavePurchaseOrder());
It has some flexibility where we can change the dependency after creation of object and also we can create object without dependencies. There is a caution of setter injection. As we can create object without dependencies, then it may through exception when using dependencies without setting/injecting them.
Interface Injection
This is not commonly used and it is complex compared to others. Dependent class implements an interface. Interface has a method signature for setting the dependencies. Injector uses the interface to set dependency. So we can say dependent class has an implementation of interface and has a method to set dependencies instead of using setter and constructor.
Let's see an example.
public interface IDependentOnTextRepository
{
void SetDependency(IRepository repository);
}
public class PurchaseBl :IDependentOnTextRepository
{
private IRepository _repository;
public string SavePurchaseOrder()
{
return _repository.Save();
}
public void SetDependency(IRepository repository)
{
_repository = repository;
}
}
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl();
((IDependentOnTextRepository)purchaseBl).SetDependency(dbRepository);
- First, we have an interface class with a setter method. Let's create that interface.
- Dependent class will implement the interface. So according to our example,
PurchaseBl
will implement IDependentOnTextRepository
. - Then finally, let's see how we can use
PurchaseBl
.
I think this is little bit complex compared to others and not commonly used.
Inversion of Control Container (IoC Container)
What is IoC Container
- Framework for doing dependency Injection
- Provides a way to configure dependencies
- Automatically resolves configured dependencies
Still not clear? Let me describe it in another way. IoC container is a framework to create dependencies and pass them when needed. That means we don’t need to manually create dependencies like earlier examples. IoC framework automatically creates objects based on request and injects them when needed. So it reduces lots of pain. You will be happy when you see all the dependencies created automatically.
What IoC Container Does
- Creates dependencies / objects
- Pass/Inject dependencies when needed
- It manages object life time
- It also stores the mapping of classes defined by the developer. Based on this mapping, your IoC container creates object.
- And does so many things….
Lots of IoC framework (Unity, Ninject, Castle Windsor, etc.) are available to use. You can download them according to your need. But before using them, I want to create IoC framework myself so that you can understand how IoC framework exactly works. Let’s visualize IoC Container. From the figure:
IoC container knows all the classes. IoC knows what are dependencies and who are dependent. When dependent class requests for an object, then IoC provides the instance of requested class based on configuration. If Dependent class requests for a class that implements IRepository
, then IoC thinks of what dependencies (DBRepository
or FakeRepository
) need to provide based on configuration.
Manual Constructor Injection
In Constructor Dependency injection section, I have showed you some example. There, I actually did manual constructor injection. Just recall them:
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl(dbRepository);
Here, I am creating dependency and after creating, I am passing that dependency to high level class. If my high level class is dependent on several low level class, then I had to create several dependencies and pass them manually. Then what does IoC container do? The answer is that the IoC Container automatically creates the dependencies and you don’t need to create them manually. I will show you how to create IoC container and how we can make them automatic and manage them from central point.
Building Own IoC Container
I know lots of IoC containers available but I am showing here how we can develop our own IoC container because it helps to understand how IoC container works. I am not going to show you details of how IoC container is created. Here, I just create a simple IoC container which can resolve dependences based configuration. Let’s start from scratch. Consider we have the following interfaces and implementations.
public interface IRepository
{
string Save();
}
And we have following implementation. Repository is responsible for storing data to database and TextRepository
is responsible for storing data to text file. Now consider a simple implementation of IRepository
:
public class Repository : IRepository
{
public string Save()
{
return "I am saving data to Database.";
}
}
class TextRepository : IRepository
{
public string Save()
{
return "I am saving data to TextFile.";
}
}
Now we have PurchaseBl
class which is dependent on IRepository
. PurchaseBl
is responsible for applying business logic and it uses IRepository
to persist its information.
public class PurchaseBl
{
private readonly IRepository _repository;
public PurchaseBl(IRepository repository)
{
_repository = repository;
}
public string SavePurchaseOrder()
{
return _repository.Save();
}
}
Our business class PurchaseBl
doesn’t know where data will be stored. So it is not depending on lower level class. We can change the persistence mechanism without changing our business class.
Let's use our PurchaseBl
with manual dependency injection first.
public static void Main()
{
IRepository dbRepository = new Repository();
PurchaseBl purchaseBl = new PurchaseBl(dbRepository);
Console.WriteLine(purchaseBl.SavePurchaseOrder());
}
Output
I am saving data to Database.
Now if we want to store our data to text file without affecting our Business layer, then we just have to make a little change on dependency creation. Let’s see:
public static void Main()
{
IRepository textRepository = newTextRepository();
PurchaseBl purchaseBl = newPurchaseBl(textRepository);
Console.WriteLine(purchaseBl.SavePurchaseOrder());
}
Output
I am saving data to TextFile.
Now we think one step further and want to use IoC Container, then what will our main method look like. Let’s see:
public static void Main()
{
Resolver resolver = new Resolver();
PurchaseBl purchaseBl = new PurchaseBl(resolver.ResolveRepository());
Console.WriteLine(purchaseBl.SavePurchaseOrder());
}
public class Resolver
{
public IRepository ResolveRepository()
{
return new TextRepository();
}
}
But the above technique is not good enough. Every time, we have to create method on Resolver
class which may increase complexity. Now let’s think another step further. We want to resolve dependences like the following:
public static void Main()
{
Resolver resolver = new Resolver();
PurchaseBl purchaseBl = resolver.Resolve<purchasebl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
}
See that we don’t need to create dependencies. IoC container automatically creates dependences and injects to PurchaseBl
class. Now our main method is more simple compared to previous. Am I right? Now our IoC container resolves dependences by reading the type of class. Here, I just showed you how to use IoC container and how to get object by passing the type only. Now let’s create our one. Here, I am adding my simple code with description.
public class Resolver
{
private readonly Dictionary<Type, Type> _dependencyMapping = new Dictionary<Type, Type>();
public T Resolve<T>()
{
return (T)Resolve(typeof(T));
}
private object Resolve(Type typeNeedToResolve)
{
Type resolvedType;
try
{
resolvedType = _dependencyMapping[typeNeedToResolve];
}
catch
{
throw new Exception(string.Format("resolve failed for {0}",
typeNeedToResolve.FullName));
}
var firstConstructor = resolvedType.GetConstructors().First();
var constructorParameters = firstConstructor.GetParameters();
if (!constructorParameters.Any())
return Activator.CreateInstance(resolvedType);
IList<object> parameterList = constructorParameters.Select(
parameterToResolve => Resolve(parameterToResolve.ParameterType)).ToList();
return firstConstructor.Invoke(parameterList.ToArray());
}
public void Registery<TFrom, TTo>()
{
_dependencyMapping.Add(typeof(TFrom), typeof(TTo));
}
}
So finally, our main method looks like the following:
public static void Main()
{
var resolver = new Resolver();
resolver.Registery<IRepository, FakeRepository>();
resolver.Registery<PurchaseBl, PurchaseBl>();
var purchaseBl = resolver.Resolve<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
}
Things You Need to Know to Use IoC Framework
If you think that the above code is complex, then you don’t need to understand it. You just need to know two things for using IoC container.
- How to configure dependencies called how to register component
- How to resolve dependencies
For resolving object, you just need to write the following code:
var purchaseBl = resolver.Resolve<purchasebl>;();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
Here, I am not saying anything about object life time management because as I said, I will create a simple IoC container so that you can understand how IoC works.
Now I want to show you how we can use another IoC container Ninject in our project.
Using Ninject IoC Container
Here, I will try to cover:
- Introduction to Ninject
- Setting up the container
- Using Container
- Lifetime management and other features
Ninject
Ninject is a newer open source IoC Container. This is simple and extensible. You can download Ninject IoC container from the following location: http://www.ninject.org/download.html. Or you can use NuGet to add ninject to your project. Let's add ninject to our project from NuGet. Just go to your project reference and right click, then ManageNuGet Packages.. then search for Nintject. You will find something like the following:
After installing Ninject, you will find Ninject on project reference. For using Ninject, you have to use following namespace:
using Ninject;
Setting Up the Container
Ninject container uses a class named kernel
. Ninject automatically registers all concrete types. You don’t need to register them.
Registering Dependencies
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<Repository>();
When IRepository
will be requested, then Repository implementation will be provided.
Using Container
Resolving Dependencies
PurchaseBl purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
It produces the following output.
Output
I am saving data to Database.
If we change the bindings, then:
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<TextRepository>();
PurchaseBl purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
It produces the following output.
Output
I am saving data to TextFile.
Rebind is very useful when we need to do something over default binding. Suppose in some times, we need to change default binding when new modules come. For rebinding, we can use Rebind
method like the following:
kernel.Rebind<IRepository>().To<Repository>();
These are simple ways in which we can use ninject. Now let's see how to manage life cycle using ninject.
Object Life Cycle Management Using Ninject
Let's modify our TextRepository
class so that we can understand our object life. The following TextRepository
is our modified class.
public class TextRepository : IRepository
{
private int _counter = 0;
public string Save()
{
_counter++;
return string.Format("I am saving data to TextFile {0}.", _counter);
}
}
Let me create two instances of PurchaseBl
like the following:
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<TextRepository();
var purchaseBl = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl.SavePurchaseOrder());
var purchaseBl2 = kernel.Get<PurchaseBl>();
Console.WriteLine(purchaseBl2.SavePurchaseOrder());
Now we have two PurchaseOrderBl
instances, purchaseBl
and purchaseBl2
. So the output is:
Output
I am saving data to TextFile1.
I am saving data to TextFile1.
Look here - both outputs showing 1, that means every time it creates new instances. Now if we want to create a single instance of TextRepository
, then we have to create instance as a Singleton so that the same instance shares through both purchaseBl
and purchaseBl2
.
Let's do that:
kernel.Bind<IRepository>().To<TextRepository>().InSingletonScope();
Output
I am saving data to TextFile1.
I am saving data to TextFile2.
Now first one returns 1 and then the second one returns 2 - that means a single instance of TextRepository
was shared by both. We can create our object in many scopes like Transaction Scope, Thread Scope, Singleton Scope and so on. These are the basics of how we can use ninject in our project. Later, I have a plan to write more details about ninject, Unity and Castle Windsor.
Conclusion
We write lots of code and after some time, we face difficulties to manage and test them. This is only because of tight coupling. Tight coupling makes our system rigid. DIP, IoC and DI helps us to write loosely couple code and make independent, modular system. Here, we saw lots of ways to make IoC. From all the techniques, Creation inversion (Dependency injection with constructor injection) is very common. I think DIP, IoC, DI and IoC container are now clear to you. I just tried to present altogether here because it helps us to understand all things related to DIP. Just remember one thing - without IDP, you cannot create independent and pluggable system. Here, I cannot describe more details because it will become too large and complicated. Thanks for reading my post!! I am expecting your valuable comments, suggestion and criticism.
Some References
History
- 7th February, 2013: Initial version