When to use Dependency Injection

2019-01-08 08:33发布

I've had a certain feeling these last couple of days that dependency-injection should really be called "I can't make up my mind"-pattern. I know this might sound silly, but really it's about the reasoning behind why I should use Dependency Injection (DI). Often it is said that I should use DI, to achieve a higher level of loose-coupling, and I get that part. But really... how often do I change my database, once my choice has fallen on MS SQL or MySQL .. Very rarely right?

Does anyone have some very compelling reasons why DI is the way to go?

8条回答
我欲成王,谁敢阻挡
2楼-- · 2019-01-08 08:59

I think that DI is worth using when you have many services/components whose implementations must be selected at runtime based on external configuration. (Note that such configuration can take the form of an XML file or a combination of code annotations and separate classes; choose what is more convenient.)

Otherwise, I would simply use a ServiceLocator, which is much "lighter" and easier to understand than a whole DI framework.

For unit testing, I prefer to use a mocking API that can mock objects on demand, instead of requiring them to be "injected" into the tested unit from a test. For Java, one such library is my own, JMockit.

查看更多
趁早两清
3楼-- · 2019-01-08 09:01

Dependency Injection gives you the ability to test specific units of code in isolation.

Say I have a class Foo for example that takes an instance of a class Bar in its constructor. One of the methods on Foo might check that a Property value of Bar is one which allows some other processing of Bar to take place.

public class Foo
{
    private Bar _bar;

    public Foo(Bar bar)
    {
        _bar = bar;
    }

    public bool IsPropertyOfBarValid()
    {
        return _bar.SomeProperty == PropertyEnum.ValidProperty;
    }
}

Now let's say that Bar is instantiated and it's Properties are set to data from some datasource in it's constructor. How might I go about testing the IsPropertyOfBarValid() method of Foo (ignoring the fact that this is an incredibly simple example)? Well, Foo is dependent on the instance of Bar passed in to the constructor, which in turn is dependent on the data from the datasource that it's properties are set to. What we would like to do is have some way of isolating Foo from the resources it depends upon so that we can test it in isolation

This is where Dependency Injection comes in. What we want is to have some way of faking an instance of Bar passed to Foo such that we can control the properties set on this fake Bar and achieve what we set out to do, test that the implementation of IsPropertyOfBarValid() does what we expect it to do, i.e. return true when Bar.SomeProperty == PropertyEnum.ValidProperty and false for any other value.

There are two types of fake object, Mocks and Stubs. Stubs provide input for the application under test so that the test can be performed on something else. Mocks on the other hand provide input to the test to decide on pass\fail.

Martin Fowler has a great article on the difference between Mocks and Stubs

查看更多
我只想做你的唯一
4楼-- · 2019-01-08 09:09

DI is very useful for decoupling your system. If all you're using it for is to decouple the database implementation from the rest of your application, then either your application is pretty simple or you need to do a lot more analysis on the problem domain and discover what components within your problem domain are the most likely to change and the components within your system that have a large amount of coupling.

DI is most useful when you're aiming for code reuse, versatility and robustness to changes in your problem domain.

How relevant it is to your project depends upon the expected lifespan of your code. Depending on the type of work you're doing zero reuse from one project to the next for the majority of code you're writing might actually be quite acceptable.

An example for use the use of DI is in creating an application that can be deployed for several clients using DI to inject customisations for the client, which could also be described as the GOF Strategy pattern. Many of the GOF patterns can be facilitated with the use of a DI framework.

DI is more relevant to Enterprise application development in which you have a large amount of code, complicated business requirements and an expectation (or hope) that the system will be maintained for many years or decades.

查看更多
forever°为你锁心
5楼-- · 2019-01-08 09:09

While I semi-agree with you with the DB example, one of the large things that I found helpful to use DI is to help me test the layer I build on top of the database.

Here's an example...

You have your database.

You have your code that accesses the database and returns objects

You have business domain objects that take the previous item's objects and do some logic with them.

If you merge the data access with your business domain logic, your domain objects can become difficult to test. DI allows you to inject your own data access objects into your domain so that you don't depend on the database for testing or possibly demonstrations (ran a demo where some data was pulled in from xml instead of a database).

Abstracting 3rd party components and frameworks like this would also help you.

Aside from the testing example, there's a few places where DI can be used through a Design by Contract approach. You may find it appropriate to create a processing engine of sorts that calls methods of the objects you're injecting into it. While it may not truly "process it" it runs the methods that have different implementation in each object you provide.

I saw an example of this where the every business domain object had a "Save" function that the was called after it was injected into the processor. The processor modified the component with configuration information and Save handled the object's primary state. In essence, DI supplemented the polymorphic method implementation of the objects that conformed to the Interface.

查看更多
倾城 Initia
6楼-- · 2019-01-08 09:10

Two words, unit testing.

One of the most compelling reasons for DI is to allow easier unit testing without having to hit a database and worry about setting up 'test' data.

查看更多
我欲成王,谁敢阻挡
7楼-- · 2019-01-08 09:11

Aside from loose coupling, testing of any type is achieved with much greater ease thanks to DI. You can put replace an existing dependency of a class under test with a mock, a dummy or even another version. If a class is created with its dependencies directly instantiated it can often be difficult or even impossible to "stub" them out if required.

查看更多
登录 后发表回答