What are the benefits of dependency injection cont

2019-01-09 23:16发布

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 kinds, etc. I'm just wondering, what are the benefits of XML configuration such as:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

compared to plain old java code such as:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

which is easier debugged, compile time checked and can be understood by anyone who knows only java. So what is the main purpose of a dependency injection framework? (or a piece of code that shows its benefits.)


UPDATE:
In case of

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

How can IoC framework guess which implementation of myService I want to be injected if there is more than one? If there is only one implementation of given interface, and I let IoC container automatically decide to use it, it will be broken after a second implementation appears. And if there is intentionally only one possible implementation of an interface then you do not need to inject it.

It would be really interesting to see small piece of configuration for IoC which shows it's benefits. I've been using Spring for a while and I can not provide such example. And I can show single lines which demonstrate benefits of hibernate, dwr, and other frameworks which I use.


UPDATE 2:
I realize that IoC configuration can be changed without recompiling. Is it really such a good idea? I can understand when someone wants to change DB credentials without recompiling - he may be not developer. In your practice, how often someone else other than developer changes IoC configuration? I think that for developers there is no effort to recompile that particular class instead of changing configuration. And for non-developer you would probably want to make his life easier and provide some simpler configuration file.


UPDATE 3:

External configuration of mapping between interfaces and their concrete implementations

What is so good in making it extenal? You don't make all your code external, while you definitely can - just place it in ClassName.java.txt file, read and compile manually on the fly - wow, you avoided recompiling. Why should compiling be avoided?!

You save coding time because you provide mappings declaratively, not in a procedural code

I understand that sometimes declarative approach saves time. For example, I declare only once a mapping between a bean property and a DB column and hibernate uses this mapping while loading, saving, building SQL based on HSQL, etc. This is where the declarative approach works. In case of Spring (in my example), declaration had more lines and had the same expressiveness as corresponding code. If there is an example when such declaration is shorter than code - I would like to see it.

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)

I do understand inversion of control benefits (I prefer to call the design pattern discussed here as Dependency Injection, because IoC is more general - there are many kinds of control, and we are inverting only one of them - control of initialization). I was asking why someone ever needs something other than a programming language for it. I definitely can replace real implementations with fake ones using code. And this code will express same thing as configuration - it will just initialize fields with fake values.

mary = new FakeFemale();

I do understand benefits of DI. I do not understand what benefits are added by external XML configuration compared to configuring code that does the same. I do not think that compiling should be avoided - I compile every day and I'm still alive. I think configuration of DI is bad example of declarative approach. Declaration can be useful if is declared once AND is used many times in different ways - like hibernate cfg, where mapping between bean property and DB column is used for saving, loading, building search queries, etc. Spring DI configuration can be easily translated to configuring code, like in the beginning of this question, can it not? And it is used only for bean initialization, isn't it? Which means a declarative approach does not add anything here, does it?

When I declare hibernate mapping, I just give hibernate some information, and it works based on it - I do not tell it what to do. In case of spring, my declaration tells spring exactly wht to do - so why declare it, why not just do it?


LAST UPDATE:
Guys, a lot of answers are telling me about dependency injection, which I KNOW IS GOOD. The question is about purpose of DI configuration instead of initializing code - I tend to think that initializing code is shorter and clearer. The only answer I got so far to my question, is that it avoids recompiling, when the configuration changes. I guess I should post another question, because it is a big secret for me, why compiling should be avoided in this case.

16条回答
放我归山
2楼-- · 2019-01-09 23:46

I have your answer

There are obviously trade offs in each approach, but externalized XML configuration files are useful for enterprise development in which build systems are used to compile the code and not your IDE. Using the build system, you may want to inject certain values into your code - for example the version of the build (which could be painful to have to update manually each time you compile). The pain is greater when your build system pulls code off of some version control system. Modifying simple values at compile time would require you to change a file, commit it, compile, and then revert each time for each change. These aren't changes that you want to commit into your version control.

Other useful use cases regarding the build system and external configs:

  • injecting styles/stylesheets for a single code base for different builds
  • injecting different sets of dynamic content (or references to them) for your single code base
  • injecting localization context for different builds/clients
  • changing a webservice URI to a backup server (when the main one goes down)

Update: All the above examples were on things that didn't necessarily require dependencies on classes. But you can easily build up cases where both a complex object and automation is necessary - for example:

  • Imagine you had a system in which it monitored the traffic of your website. Depending on the # of concurrent users, it turns on/off a logging mechanism. Perhaps while the mechanism is off, a stub object is put in its place.
  • Imagine you had a web conferencing system in which depending on the # of users, you want to switch out the ability to do P2P depending on # of participants
查看更多
迷人小祖宗
3楼-- · 2019-01-09 23:46

In the .NET world, most of IoC frameworks provide both XML and Code configuration.

StructureMap and Ninject, for example, use fluent interfaces to configure containers. You are no longer constrained to use XML configuration files. Spring, which also exists in .NET, heavily relies on XML files since it is his historical main configuration interface, but it is still possible to configure containers programmatically.

查看更多
萌系小妹纸
4楼-- · 2019-01-09 23:48

For myself one of the main reasons to use an IoC (and make use of external configuration) is around the two areas of:

  • Testing
  • Production maintenance

Testing

If you split your testing into 3 scenarios (which is fairly normal in large scale development):

  1. Unit testing
  2. Integration testing
  3. Black box testing

What you will want to do is for the last two test scenarios (Integration & Black box), is not recompile any part of the application.

If any of your test scenarios require you to change the configuration (ie: use another component to mimic a banking integration, or do a performance load), this can be easily handled (this does come under the benefits of configuring the DI side of an IoC though.

Additionally if your app is used either at multiple sites (with different server and component configuration) or has a changing configuration on the live environment you can use the later stages of testing to verify that the app will handle those changes.

Production

As a developer you don't (and should not) have control of the production environment (in particular when your app is being distributed to multiple customers or seperate sites), this to me is the real benefit of using both an IoC and external configuration, as it is up to the infrastructure/production support to tweak and adjust the live environment without having to go back to developers and through test (higher cost when all they want to do is move a component).

Summary

The main benefits that external configuration of an IoC come from giving others (non-developers) the power to configure your application, in my experience this is only useful under a limited set of circumstances:

  • Application is distributed to multiple sites/clients where environments will differ.
  • Limited development control/input over the production environment and setup.
  • Testing scenarios.

In practice I've found that even when developing something that you do have control over the environment it will be run on, over time it is better to give someone else the capabilities to change the configuration:

  • When developing you don't know when it will change (the app is so useful your company sells it to someone else).
  • I don't want to be stuck with changing the code every time a slight change is requested that could have been handled by setting up and using a good configuration model.

Note: Application refers to the complete solution (not just the executable), so all files required for the application to run.

查看更多
我想做一个坏孩纸
5楼-- · 2019-01-09 23:50

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.

查看更多
贪生不怕死
6楼-- · 2019-01-09 23:51

Often, the important point is who is changing the configuration after the program was written. With configuration in code you implicitly assume that person changing it has the same skills and access to source code etc as the original author had.

In production systems it is very practical to extract some subset of settings (e.g. age in you example) to XML file and allow e.g. system administrator or support personal to change the value without giving them the full power over source code or other settings - or just to isolate them from complexities.

查看更多
Luminary・发光体
7楼-- · 2019-01-09 23:52

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)
查看更多
登录 后发表回答