What is the advantage of dependency injection over an instance of an object?

I have read and reread what is Dependency Injection? but ultimately I couldn't realize an advantage of dependency injection over an object instance.

  • What is the advantage of dependency injection over an instance of an object?

Addition:

Service service = new Service();

For:

IService _service;

public Construtor(IService service)
    _service = service;
}

I went searching and ended up finding Difference between creating new object and dependency injection , but not who answered the question know how to say this difference.

Author: Maniero, 2018-09-03

3 answers

In essence the advantage is flexibility.

Understand that DI (Dependency Injection) is a pompous name for something very simple. I already talked about this in a couple of question and answer my . Just parameterize an object you need in a certain place, be it an algorithm or structure.

When you accept a parameter with the object that should be used in the method, and that can optionally be stored in an instance of another object, you can work with objects of different types that accept the same contract. So the advantage is almost the same as accepting parameter in anything else. Example:

metodo() => for (int i = 0; i < 10; i++) print(i);

Now with parameter, which does not cease to be a dependency that you are injecting (you depended on a value that is fixed there in the code, now depends on the parameter):

metodo(int x) => for (int i = 0; i < x; i++) print(i);

Has now become more flexible. Simple, right? So obvious that no one thinks about it. Now exchange the int for a more complex object and have what you wrote in the question.

Of course there is something else in the DI mechanism that is known, you do not with the same type of object, but with the same base type, so you can be more flexible using the polymorphism mechanism.

See programming facing interface and not implementation, why?.

If you know you will always use the same type then it doesn't make much sense to use this mechanism. Generally the use of Di viola or YAGNI . The service case can be necessary even, however the use of services may be questioned, not always need in fact. It can be just a complication created to follow the current fashion. It may be that you need the service, but you do not need to parameterize it, or at least you do not always need it. It can have something like this:

class SeiLá {
    public Método() {
        Service service = new Service();
        ...
    }
    public Méwtodo(IService service) {
        ...
    }
}

Forcing the programmer to create an instance at the place of consumption is the end of the sting. Even more so if it is used just like that for testing.

Tests

If it's just because of the test do like this:

class SeiLá {
    public Metédo() {
        Service service = new Service();
        ...
    }
    [Debug] //ou use aqui outro mecanismo que nem mande para o executável este método
    public Metodo(IService service) {
        ...
    }
}

Those who like to take tests use a lot of DI just because of the test. I don't like it and I think the language and tools you use should take care of it. You shouldn't have to change the design of your application to meet a requirement unique to the test but not within the domain of the problem you are solving. There are those who disagree.

When going to test something complex can get slow, depend on some heavy mechanism, expensive and that may not be available at the time of the test, or still that you have no control over the answer it will give. To ensure that the test is adequate and light, you replace the original engine that you could use direct with another simple and controlled by you, so when you go to test you call by passing an object of the same contract, that is, derived from an equal class or interface, then it performs everything it needs differently.

What no one tells you is that between the test and the real it can have so much different that the test may not have the relevance you expect, or to have it may incur cost incompatible with the project.

These days I saw a talk from a person talking about testing, then talking to the person she said she was only testing a crucial part of the system. Now, in the lecture you gave the impression that it was everything. That without testing can not do anything. People do a lot of this, they speak something that they do not even practice, just because it is pleasant to talk about what is in the fashion and that people will applaud, but maybe the person does not even know why he uses it, yet he puts himself as an expert.

In your example instead of using a real service you use one that answers what you want to test in a simple, direct and controlled way, and running lightly.

How would you change this during testing without a parameter? If the language helps and allows you to write this selection according to some compilation variable or some tool that manipulates the code at compile time or even at some point next does so with little or zero intervention in the code itself. That's the right way, but most of the tools you have out there don't. This is what I repeat: people, even first-rate engineers, follow a lot of ready-made formulas, do not think about what the real problem is and what is the appropriate solution to solve it. There they put in the domain what is auxiliary mechanism.

If the test was run during use in production of course it would make sense, but if it is test of design and manufacturing it makes no sense to keep hangers on it.

Today I even question the necessary flexibility. For testing I question much more. Should resolve at compile time. Dependency Injection is a runtime solution, and most of the time you already know at compile time how to solve that, so leave that burden behind?

A better solution is to use generics (I'm not saying that for this case is the best solution):

class SeiLá<T> where T : IService {
    public Método() {
        T service = new T();
        ...
    }
}

I made it flexible without having to resolve at runtime (depends on implementation), without creating a variable in the instance. But note that this is suitable for when you need to change even, if it is just to test I think even this an exaggeration. This is DI with parametric polymorphism.

If it is just for testing it is complicated to post something here because it depends on specific tools, and that almost always does not they are available, and in many cases you would have to develop because it gets a lot of people following the wrong caravan and fail to do the right thing. A rough shape:

class SeiLá {
    public Método() {
        #TService service = new #TService();
        ...
    }
}

Where TService is a build variable and # is what is used to indicate this.

Reason for runtime

I usually say that there are only two reasons to solve something at runtime:

  • the data is only available at the time of execution, depends on input from user data by keyboard, mouse, microphone, or other input device or that comes from Network, File System, database, miscellaneous services, or something that the operating system reports on time, such as the time itself, for example.
  • for convenience, then it could solve in the compilation, but the code will become more complex, more difficult to write and understand, to maintain, higher in the binary, slower, etc.

Conclusion

If it's something from system and does not come from outside, always has how to solve in the compilation. Then you decide what will make the code simpler, faster, more robust, use DI when meeting this (tip: people use it even when it makes the code more complicated, slower and less robust, but in the name of robustness). Almost always it is not using DI. But it's a lost battle. This lie has been told so many times that many people think it should always use.

DI is just a specific way to use polymorphism. To instance of the object you will have anyway, the question is whether it will determine the type of the object in the code that is working now or let the consumer of it determine which one it is.

Plastic chair in place of original car seat

 21
Author: Maniero, 2020-08-04 12:00:44

An example of code using instance of an object.

public interface DebugInterface {

    void error(string message);

}

public class Debug implements DebugInterface {

    public void error(string message) {
        // código que faz uma coisa com a mensagem
    }
}

...

// Para você usar seria.
DebugInterface debug = new Debug();

Now imagine that you use this class in various parts of your code and you want to replace this implementation with another, you would have to replace every line in every class that is importing Debug and every line in which you implement Debug. The amount of modifications varies from language to language, but overall, you would have to make several modifications.

Using Dependency Injection, you do not you would have to replace Line by line if you want to replace the old Debug with another class like:

public class DebugModificado implements DebugInterface {

    public void error(string message) {
        // faz outra coisa com a mensagem
    }
}

...
// E substuir cada linha de
DebugInterface debug = new Debug();

// Para
DebugInterface debug = new DebugModificado();

This implementation would be done in another part of the code (it varies from language to language), and your code would look like this:

DebugInterface debug = new DebugInterface();

That way, whenever you wanted to change the implementation of this interface, you would only have to change one line of code (which would be where you define the dependency injection).

 6
Author: Vinicius Lourenço, 2018-09-03 23:42:06

The answer about what is Dependency Injection has already been answered in some posts on the network.

To try to make it easier let's say the following:

Whenever we want to create an object it is necessary to use the word new and in this case whenever you need an object of type person you have to use new Pessoa().

this is where the addiction injection makes the difference.

It exists so that the code is cleaner and efficient. Think of dependency injection as global variables that can be accessed in all programs.

For example imagine you have a service that is unique in your program or a class that is unique as a connection to a database. So you take advantage of the dependency injection where instead of creating a new connection every time you need to connect to the database, you make use of the one you created at the beginning of the program.

Example in Angular:

import {UsersService} from './users.service';

constructor(private usersService: UsersService) { }

Use

this.usersService.getUsers().subscribe(res =>this.users = res);

This way you're always using the same object and you don't have to create new objects to do the same.

 3
Author: Tiago Neiva, 2018-09-10 18:50:20