I've heard a lot about dependency injection. The question is: How, when and what to use?
I've heard a lot about dependency injection. The question is: How, when and what to use?
Great subject, however, this gives a response book.
I recommend the Design Patterns study.
It is a Design Pattern that preaches an external control type, container, class, settings via file, etc., to insert a dependency into another class.
Trying to improve: "The dependency injection pattern aims to remove unnecessary dependencies between classes."
public class PedidosController : Controller
{
private IPedidoRepository _pedidoRepositorio;
public PedidosController(IPedidoRepository pedidoRepositorio)
{
_pedidoRepositorio = pedidoRepositorio;
}
public ActionResult Index()
{
var pedidos = _pedidoRepositorio.ObterTodos();
return View(pedidos);
}
}
In order to understand the concept it is also necessary to deepen the knowledge in Inversion of Control and a little of the SOLID principle, after all it is the Letter D (Depend on an abstraction and not an implementation) / p>
Example of something wrong, something very coupled.
public class PedidosController : Controller
{
public ActionResult Index()
{
var pedidoRepositorio = new PedidoRepository();
var pedidos = pedidoRepositorio.ObterTodos();
return View(pedidos);
}
}
And the great Martin Fowler:
Dependency injection is a type of Control Inversion and means that a class is no longer responsible for creating or fetching the objects it depends on.
This serves to uncouple the classes, avoiding direct dependency between them.
The results are:
I'll illustrate a simple case of Dependency Injection without a container or framework .
Suppose you have a system that processes payments and implements a method as follows:
class Pagamento {
void efetuarPagamento(String tipo, Integer codigo, Double valor) {
if ("BOLETO".equals(tipo)) {
new IntegracaoBoletoBanco().pagarBoleto(codigo, valor);
} else if ("CARTAO".equals(tipo)) {
new IntegracaoCartaoBanco().pagarCartao(codigo, valor);
} else if ("DINHEIRO".equals(tipo)) {
new IntegracaoContaBanco().pagarDinheiro(codigo, valor);
}
}
}
Note that the method directly instantiates several classes. This is very bad because the code gets all coupled and maintenance is needed whenever some implementation changes.
We can refactor this code so that the algorithm becomes more generic. Let's see:
class Pagamento {
IntegracaoBanco integracaoBanco;
public Pagamento(IntegracaoBanco integracaoBanco) {
this.integracaoBanco = integracaoBanco;
}
void efetuarPagamento(Integer codigo, Double valor) {
integracaoBanco.pagar(codigo, valor);
}
}
Here, IntegracaoBanco
is an interface and can receive multiple implementations. In addition, class now requires that one of these implementations be passed in the constructor.
Our class no longer has the responsibility to know the implementations of IntegracaoBanco
. Who is going to call it is who should pass the correct instance, injecting this dependency at the time of creating the class.
This time our code has become much simpler and allows you to create new payment implementations through the interface or extend the classes that are already part of the system without touching the existing code.
See more examples that involve Reverse Control in my answers here at SOPT:
This SOEN answer deserves be translated and left here for reference:
How to explain dependency injection to a 5-year-old boy?
When you go to the fridge (refrigerator, in pt_BR) you can get something for yourself, it can cause problems. You can leave the door open, you can take anything the Father or the Mother does not want you to eat. You can even search for anything we do not have or find something that has expired.
What you should do is say what you need, "I need anything to drink at lunch," and then I'll make sure you get what you need when you snack.
Edit:
A simple example of dependency injection.
No dependency injection:
public void Test()
{
Logger newLogger = new Logger(...);
newLogger.Debug("");
}
Assuming that the Logger class implements the ILogger interface, you can inject the Logger as follows:
public void Test(ILogger logger)
{
logger.Debug("");
}
In this way, the responsibility and knowledge of how to instantiate the Logger class stayed for the code that calls the Test method.
Second article, which I had the audacity to translate it, written by Steve Smith and Scott Addie on 10/02/2017 for Microsoft ...
Dependency injection is a technique for ridding or removing the coupling between objects and their collaborators, or dependents. Instead of instantiating collaborative objects directly, or using static references; these collaborators are supplied to the dependent class in a particular way. Generally, these classes will declare their dependencies through their constructors, thus following the Principle of Explicit Dependencies. This way of performing a dependency injection is known as "Builder Injection."
When classes are developed, taking into account dependency injection, they are less coupled, because there is no code referencing them directly on their dependents. This form follows the "Dependency Inversion Principle", which states: "High-level modules should not rely on low-level modules, both of which should depend on abstractions." Instead of referencing a specific implementation, dependent classes must request abstractions (usually Interfaces), which are provided to them when the class is created. Extracting dependents into interfaces and providing implementations of these interfaces as parameters are also examples of the Standard Development Strategy.
When a system is designed to use Dependency Injection with many dependency requests via constructor (or properties), it is useful to have a dedicated class to create these classes along with their associated dependencies. These classes are referred to as repositories, or more specifically, Reverse Control (IoC) repositories or Dependency Injection (DI) repositories. "A repository is essentially a factory that is responsible for providing instances of types that are required of them If a particular type declared that it has dependencies, and the repository has been configured to provide type dependencies, it will create the dependencies as part of the instance creation request, so a complex dependency string can be supplied to class without no fixed code is inserted into its constructor.In addition to creating objects with their dependencies, repositories generally manage the lifecycle of the object in the application.
ref: link (accessed 9/21/2017).