Do I understand DI / IoC correctly?

I am currently trying to learn the benefits of using an IoC container and familiarize myself with the DI. I started using StructureMap as it seems quite simplistic and yet powerful.

I want to check if I understand these concepts correctly. Let us assume the following rudimentary classes in the application (details for brevity):

public class OrderService : IOrderService { private IOrderRepository _repository; private ITaxCalculator _taxCalculator; private IShippingCalculator _shippingCalculator; public OrderService(IOrderRepository repository, ITaxCalculator taxCalculator, IShippingCalculator shippingCalculator) { this._repository = repository; this._shippingCalculator = shippingCalculator; this._taxCalculator = taxCalculator; } public IOrder Find(int id) { return this._repository.Find(id); } } public class OrderRepository : IOrderRepository { public IOrder Find(int id) { // ... } } public class StandardShippingCalculator : IShippingCalculator { // ... } public class StandardTaxCalculator : ITaxCalculator { private ITaxSpecification _specification; public StandardTaxCalculator(ITaxSpecification specification) { this._specification = specification; } } 

First of all, the principle of dependency inversion states that since the OrderService is a “high-level” module, it will not depend on the details of the implementation of anything of a lower level, it should just have references to these classes and be able to ask them to do their job without knowing what it does, and the consumer code must be responsible for creating and passing these pre-configured modules. It is right? Therefore, the DI keeps these classes loosely coupled, so they don’t need to know exactly how the method is called for this dependency, just so that it is called and does whatever it needs, the OrderService does not care if it requests the Repository XML or uses NHibernate or EF or even raw DataSets; he just knows that he can call the repository, tell him to find the order with identifier 42, and the repository will know what to do.

I also understand that the IoC container, StructureMap in this case provides benefits, without forcing us to make sure that we create all these dependencies manually and pass them. For example, the main method of a trivial application using the above code may have:

 static void Main(string[] args) { IOrderService service = new OrderService( new OrderRepository(), new StandardShippingService(), new StandardTaxService(new StandardTaxSpecification())); IOrder order = service.Find(42); // Do something with order... } 

which is disgustingly ugly with all the news to set it up; even if I created the variables, they are still ugly. Using an IoC container allows me to avoid all of this, and in the case of StructureMap, this will be as follows:

 static void Main(string[] args) { ObjectFactory.Initialize(x => { x.For<IOrderRepository>().Use<OrderRepository>(); x.For<IOrderService>().Use<OrderService>(); x.For<IOrder>().Use<Order>(); x.For<IShippingCalculator>() .Use<StandardShippingCalculator>(); x.For<ITaxCalculator>().Use<StandardTaxCalculator>(); x.For<ITaxSpecification>() .Use<StandardTaxSpecification>(); }); IOrderService service = ObjectFactory.GetInstance<IOrderService>(); IOrder order = service.Find(42); // do stuff with order... } 

Which is much cleaner, easier to maintain, and allows me to simply exclude a specific class, say for Mock, if I wrote unit test. In short, the advantage is that it further separates everything that I don’t even need (in the call code, that is), on which particular class it depends, I can simply create it using the container and let it do this and provide so that the consumer code knows only what it needs - for example, in a real application, if the controller calls the service, it does not need to know about repositories or calculators or specifications, all it needs to know is to use OrderService to do something with The Order.

It is right? There are a few things in this post that I'm not sure about yet:

  • If you decide to use an IoC container, is it intended to be used throughout the application, only if you have many inverted dependencies for the solution, or only the consumer? For example, in OrderRepository, if I use a specific implementation and create an order; Will this class use StructureMap to receive an order? This may be a bit of a dumb question, but all the DI / IoC examples I've seen focus only on using it in a consumer client (like a web page) and never relate to using it elsewhere. This seems to be an all-or-nothing approach: if you intend to use an IoC container, it will be used everywhere; you essentially replace any call with new SomeObject(); , in this case ObjectFactory.GetInstance<ISomeObject>();

  • It is considered good or bad that every class (where possible, of course) flow from the interface, do I need to use DI / IoC or something like taunts? I have seen many code examples in which each individual class that does not have an embedded interface has an interface behind it, and although I see the benefits and possible future verification of this, and I believe that the following TDD or BDD may be a factor here, like using these methodologies will usually tell you if you need an interface for a class, but I have seen and talked with many people who, TDD or not, think that you should never define an object type as a concrete class; it should always be an interface or an abstract class as a base type. This is similar to the case of the "Needless Complexity" code smell, not to mention a violation of YAGNI.

+8
dependency-injection inversion-of-control solid-principles
source share
2 answers

Both questions are controversial, but I will weigh the debate on my side.

If you decide to use the IoC container, does it mean that it is used throughout the application, only where you have many inverted dependencies for the solution, or only the consumer?

Your top-level application (consumer) is the only component you need to know about your dependency injection infrastructure. You do not need to replace new with your entire codebase, because each object must have all instances of the dependencies that it needs to do its job (Miško Hevery " Myth: Reference Passing " was what finally drove this house for me).

It is considered good or bad to have every class (where possible, from the course) derives from the interface whether it is necessary to use DI / IoC or something like ridicule?

The rest of this question shows that you already know the answer to this question: just create interfaces to create more suitable abstractions (than a particular class) or to provide a different value.

+4
source share

I am currently working with DI / IoC in C # / WinForm on VisualStudio2010 / 12. My choice depends on Castle Windsor, but also on StructureMap, but it doesn't matter which IoCC you use.

For a very detailed answer, I suggest you read Mark Seeman's “Dependency Injection in .NET”. This is a good book, even if you are not developing .NET.

Regarding your questions:

  • A DI CONTAINER is a library that you can use wherever you are, for example, but that does not mean you should. Although you can have the container permeate a large percentage of your activities, you should instead focus on one area of ​​your application.

    This place is called COMPOSITION COURT, and you should use only the DI CONTAINER from this place. COMPOSITION OF THE APPLICATION CORPORATION must be located in root applications so that it can correctly compose the application. You should not try to compose classes in any of the modules, because the approach limits your options. All classes in application modules must use CONSTRUCTOR INJECTION (or, in rare cases, one of the other templates, such as Property Injection) and leave it up to ROOM COMPOSITION to graph application objects. Any DI-CONTAINER call should be limited to ROOT COMPOSITION.

    COMPOSITION OF COWS can be divided into several classes. This is expected - it is important that all classes are contained in the same module, which is preferably the root of the application.

  • You do not need to use interfaces everywhere. You can also use specific classes. Of course, interfaces provide a higher level of abstraction, but you have to consider if you need to in your project. For example, it’s good practice to use the interface in the business logic in your application.

+1
source share

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


All Articles