📜 ⬆️ ⬇️

IoC, DI, IoC-container - Just a simple

I think now the words IoC, DI, IoC-container, at least many are heard. Some actively use this, others are trying to understand what kind of fashion trends.

At the moment, on this topic it is already enough said, written, including on the habr, but just because of the abundance of information it is difficult to find really useful content. In addition, these concepts are often confused and / or confused. After analyzing a variety of materials, I decided to present you my vision of the subject.

Theory


For me, the relationship between IoC and DI is the same as between Agile and Scrum, i.e.
Inversion of Control is a kind of abstract principle, a set of recommendations for writing loosely coupled code. The essence of which is that each component of the system should be as isolated as possible from the others, not relying in its work on the details of the specific implementation of other components.
Dependency Injection (dependency injection) is one of the implementations of this principle (in addition, there is also the Factory Method , Service Locator ).
IoC-container is some kind of library, framework, program if you want, which will allow you to simplify and automate the writing of code using this approach as much as possible. There are quite a few of them, use what is convenient for you, I will demonstrate everything with the example of Ninject .

Practice


According to the management inversion approach, if we have a client who uses a certain service, then he should do it not directly, but through an intermediary, a kind of outsourcing.
The scheme of customer interaction with the service
How technically it will be done and determines each of the implementations of the IoC approach.
We will use DI, on a simple example:
Let's say there is a class that creates a schedule, and another class displays it (there are usually many of them, say one for a desktop application, another for the web, etc.).
If we didn’t know anything about IoC, we would write something like this:
class ScheduleManager { public Schedule GetSchedule() { // Do Something by init schedule... } } class ScheduleViewer { private ScheduleManager _scheduleManager = new ScheduleManager(); public void RenderSchedule() { _scheduleManager.GetSchedule(); // Do Something by render schedule... } } 

It seems to be all right, the code solves the task, but what if we want to later change the implementation of the schedule manager and / or have several such managers and dynamically replace them. Then, in the future, we will have to change something in ScheduleViewer, and therefore test it again.
Fortunately, developers, lazy people in a good sense of the word, and do not like to do the same thing twice.
')
For example, we will use dependency injection (DI) to break this tangle of steel threads - we will make the connection between these classes weaker by adding a layer in the form of the IScheduleManager interface. And we will resolve it with one of the DI technique methods, namely Constructor Injection (in addition, there is Setter Injection and Method Injection - if in two words, then the interface is used instead of a specific class, for example, in a property type or in a method argument type):
 interface IScheduleManager { Schedule GetSchedule(); } class ScheduleManager : IScheduleManager { public Schedule GetSchedule() { // Do Something by init schedule... } } class ScheduleViewer { private IScheduleManager _scheduleManager; public ScheduleViewer(IScheduleManager scheduleManager) { _scheduleManager = scheduleManager; } public void RenderSchedule() { _scheduleManager.GetSchedule(); // Do Something by render schedule... } } 

And then where we want to use our class to display the schedule, we write:
 ScheduleViewer scheduleViewer = new ScheduleViewer(new ScheduleManager()); 

Now it's almost perfect, but what if we have a lot of different ScheduleViewer scattered around the project, which is always used by the ScheduleManager (you have to create it every time) and / or we want to customize the behavior in some way, so that we can use ScheduleManager, and in another we will say AnotherScheduleManager, etc.
IoC containers are designed to solve this problem.

IoC containers


They help reduce the amount of routine, allowing you to set the correspondence between the interface and its specific implementation, so that you can use it everywhere.
As I said above, we will look at this using the example of Ninject -
1. First, we create a container configuration:
 class SimpleConfigModule : NinjectModule { public override void Load() { Bind<IScheduleManager>().To<ScheduleManager>(); //   ,     : // ..     Bind<ScheduleViewer>().ToSelf(); } } 

Now everywhere where IScheduleManager is required, ScheduleManager will be substituted.
2. Create the container itself, specifying its configurator:
 IKernel ninjectKernel = new StandardKernel(new SimpleConfigModule()); //      ScheduleViewer   new,  : ScheduleViewer scheduleViewer= ninjectKernel.Get<ScheduleViewer>(); 

The container itself will create an instance of the ScheduleManager class, invoke the ScheduleViewer constructor and insert into it a newly created ScheduleManager instance.

Conclusion


And finally, I want to say that IoC, DI is a very good tool, but like any other mechanism, you need to use it consciously and to the point. Let's say one small console application is one thing, in which something is unlikely to change, or a serious large project where the customer’s wishes are often changeable and contradictory.
That's all, I will be very happy to hear your comments, constructive comments.
Good luck to all deploy on production.

Source: https://habr.com/ru/post/131993/


All Articles