What are the benefits of dependency injection containers?

前端 未结 16 2617
南笙
南笙 2020-12-02 04:09

I understand benefits of dependency injection itself. Let\'s take Spring for instance. I also understand benefits of other Spring featureslike AOP, helpers of different kind

相关标签:
16条回答
  • 2020-12-02 04:40

    Dependency injection is a coding style that has its roots in the observation that object delegation is usually a more useful design pattern than object inheritance (i.e., the object has-a relationship is more useful than the object is-a relationship). One other ingredient is necessary however for DI to work, that of creating object interfaces. Combining these two powerful design patterns software engineers quickly realized that they could create flexible loosely coupled code and thus the concept of Dependency Injection was born. However it wasn't until object reflection became available in certain high level languages that DI really took off. The reflection component is core to most of today's DI systems today because the really cool aspects of DI require the ability to programmatically select objects and configure and inject them into other objects using a system external and independent to the objects themselves.

    A language must provide good support for both normal Object Oriented programming techniques as well as support for object interfaces and object reflection (for example Java and C#). While you can build programs using DI patterns in C++ systems its lack of reflection support within the language proper prevents it from supporting application servers and other DI platforms and hence limits the expressiveness of the DI patterns.

    Strengths of a system built using DI patterns:

    1. DI code is much easier to reuse as the 'depended' functionality is extrapolated into well defined interfaces, allowing separate objects whose configuration is handled by a suitable application platform to be plugged into other objects at will.
    2. DI code is much easier to test. The functionality expressed by the object can be tested in a black box by building 'mock' objects implementing the interfaces expected by your application logic.
    3. DI code is more flexible. It is innately loosely coupled code -- to an extreme. This allows the programmer to pick and choose how objects are connected based exclusively on their required interfaces on one end and their expressed interfaces on the other.
    4. External (Xml) configuration of DI objects means that others can customize your code in unforeseen directions.
    5. External configuration is also a separation of concern pattern in that all problems of object initialization and object interdependency management can be handled by the application server.
    6. Note that external configuration is not required to use the DI pattern, for simple interconnections a small builder object is often adequate. There is a tradeoff in flexibility between the two. A builder object is not as flexible an option as an externally visible configuration file. The developer of the DI system must weigh the advantages of flexibility over convenience, taking care that small scale, fine grain control over object construction as expressed in a configuration file may increase confusion and maintenance costs down the line.

    Definitely DI code seems more cumbersome, the disadvantages of having all of those XML files that configure objects to be injected into other objects appears difficult. This is, however, the point of DI systems. Your ability to mix and match code objects as a series of configuration settings allows you to build complex systems using 3rd party code with minimal coding on your part.

    The example provided in the question merely touches on the surface of the expressive power that a properly factored DI object library can provide. With some practice and a lot of self discipline most DI practitioners find that they can build systems that have 100% test coverage of application code. This one point alone is extraordinary. This is not 100% test coverage of a small application of a few hundred lines of code, but 100% test coverage of applications comprising hundreds of thousands of lines of code. I am at a loss of being able to describe any other design pattern that provides this level of testability.

    You are correct in that an application of a mere 10s of lines of code is easier to understand than several objects plus a series of XML configuration files. However as with most powerful design patterns, the gains are found as you continue to add new features to the system.

    In short, large scale DI based applications are both easier to debug and easier to understand. While the Xml configuration is not 'compile time checked' all application services that this author is aware of will provide the developer with error messages if they attempt to inject an object having an incompatible interface into another object. And most provide a 'check' feature that covers all known objects configurations. This is easily and quickly done by checking that the to-be-injected object A implements the interface required by object B for all configured object injections.

    0 讨论(0)
  • 2020-12-02 04:42

    From a Spring perspecitve I can give you two answers.

    First the XML configuration isn't the only way to define the configuration. Most things can be configured using annotations and the things that must be done with XML are configuration for code that you aren't writing anyways, like a connection pool that you are using from a library. Spring 3 includes a method for defining the DI configuration using Java similar to the hand rolled DI configuration in your example. So using Spring does not mean that you have to use an XML based configuration file.

    Secondly Spring is a lot more than just a DI framework. It has lots of other features including transaction management and AOP. The Spring XML configuration mixes all these concepts together. Often in the same configuration file I'm specifying bean dependencies, transaction settings and adding session scoped beans that actually handled using AOP in the background. I find the XML configuration provides a better place to manage all these features. I also feel that the annotation based configuration and XML configuration scale up better than doing Java based configuration.

    But I do see your point and there isn't anything wrong with defining the dependency injection configuration in Java. I normally do that myself in unit tests and when I'm working on a project small enough that I haven't added a DI framework. I don't normally specify configuration in Java because to me that's the kind plumbing code that I'm trying to get away from writing when I chose to use Spring. That's a preference though, it doesn't mean that XML configuration is superior to Java based configuration.

    0 讨论(0)
  • 2020-12-02 04:44

    One of the most appealing reasons is the "Hollywood principle": don't call us, we'll call you. A component is not required to do the lookups to other components and services itself; instead they are provided to it automatically. In Java, this means that it is no longer necessary to do JNDI lookups inside the component.

    It is also lots easier to unit test a component in isolation: instead of giving it an actual implementation of the components it needs, you simply use (possibly auto generated) mocks.

    0 讨论(0)
  • 2020-12-02 04:45

    Your case is very simple and therefore doesn't need an IoC (Inversion of Control) container like Spring. On the other hand, when you "program to interfaces, not implementations" (which is a good practice in OOP), you can have code like this:

    IService myService;
    // ...
    public void doSomething() {
      myService.fetchData();
    }
    

    (note that the type of myService is IService -- an interface, not a concrete implementation). Now it can be handy to let your IoC container automatically provide the correct concrete instance of IService during initialization - when you have many interfaces and many implementations, it can be cumbersome to do that by hand. Main benefits of an IoC container (dependency injection framework) are:

    • External configuration of mapping between interfaces and their concrete implementations
    • IoC container handles some tricky issues like resolving complicated dependency graphs, managing component's lifetime etc.
    • You save coding time because you provide mappings declaratively, not in a procedural code
    • Inversion of Control principle allows for easy unit testing because you can replace real implementations with fake ones (like replacing SQL database with an in-memory one)
    0 讨论(0)
  • 2020-12-02 04:45

    Initializing in an XML config file will simplify your debugging / adapting work with a client who has your app deployed on their computers. (Because it doesn't require recompilation + binary files replacement)

    0 讨论(0)
  • 2020-12-02 04:49

    You don't need to recompile your code each time you change something in configuration. It will simplify program deployment and maintenance. For example you can swap one component with another with just 1 change in config file.

    0 讨论(0)
提交回复
热议问题