In software engineering, dependency injection is a technique in which one object (or static method) supplies the dependencies of another object. Dependency is a usable object (service). Injection is the negligence of dependence to the dependent object (client) that will use it. This service is part of the client's country. Passing the service to clients, rather than letting clients build or find services, is a fundamental requirement of the pattern.
This basic requirement means that using the value (service) generated in the class of a new or static method is prohibited. The client must accept the forwarded value from the outside. This allows the client to create dependency issues acquiring others.
The intent behind the injection dependence is to separate the object to the extent that no client code should be changed simply because the object depends on the need to be changed to a different one.
Dependency injection is one form of wider inversion control technique. Like other forms of inversion control, dependency injection supports the principle of inversion dependencies. The client delegates the responsibility to provide its dependencies to the external code (injector). Client is not allowed to invoke injector code; it is the code that injects the build service and calls the client to inject it. This means the client code does not need to know about the injection code, how to build the service or even the actual service being used; the client only needs to know about the intrinsic interface of the service because it determines how clients can use the service. It separates responsibility for use and construction.
There are three common ways for clients to accept dependency injection: setter-, interface, and constructor-based injection. Setter and injection constructors differ especially when they can be used. The injection interface differs in the dependency given the chance to control the injection itself. Each requires a separate construction code (injector) to take responsibility for introducing clients and their dependence on each other.
Video Dependency injection
Intent
Dependency Injection design patterns solve problems such as:
- How can an application be independent of how its object is created?
- How can a class be detached from how the required object is created?
- How do I create an object specified in a separate configuration file?
- How can applications support different configurations?
Creating objects directly in a class that requires an inflexible object because it does a class to a particular object and makes it impossible to change instantiation later independently of (without having to change) the class. It stops the class from being reusable if another object is needed, and it makes the class difficult to test because the real object can not be replaced with an artificial object.
The Dependency Injection design pattern explains how to solve such problems:
- Specifies a separate object (injector) that creates and injects objects that the class needs.
- The class receives the required object from the injector object rather than creating the object directly.
This makes the class independent of how objects are created (which concrete class is used) The class is no longer responsible for creating the required objects, and does not need to delegate instantiation to the factory object as in the Abstract Factory design pattern.
It greatly simplifies the class and makes it easier to apply, change, test, and reuse See also UML class and sequence diagram below.
Maps Dependency injection
Overview
Dependency injection separates the client-dependent creation of client behavior, allowing the program design to be loosely coupled and following the inversion of dependencies and the principle of sole responsibility. This directly contrasts with the pattern of the service locator, which allows clients to know about the systems they use to find dependencies.
Injection, the basic unit of dependency injection, is not a new mechanism or habit. It works in the same way as the "passing parameter" works. Referring to "passing parameters" as injections brings additional implications to isolate clients from detail.
The injection is also about what controls the graduation (never the client) and does not depend on how the graduation is achieved, whether by giving references or grades.
Dependency injection involves four roles:
- the services object to use
- the client object that depends on the services it uses
- the interface that determines how clients can use the service
- injector , which is responsible for creating the service and injecting it into clients
Any usable object can be considered a service . Any object that uses another object can be considered a client . The names have nothing to do with what those objects are for and all that needs to be done with the role that the object plays in one shot.
The Interface is the type clients expect to be dependent on. The problem is what they make accessible. They may actually be the type of interface that the service implements, but can also be an abstract class or even a concrete service themselves, although the latter would violate the DIP and sacrifice the dynamic decoupling that allows testing. It only takes that the client does not know which of them and hence never treats them as concrete, say by building or expanding it.
The client should have no concrete knowledge of the specific implementation of its dependencies. It should only know the interface name and API. As a result, the client does not need to change even if what is behind the interface changes. However, if the interface is factored from the class to the interface type (or vice versa) the client must be recompiled. This is significant if clients and services are published separately. This poor clutch is one of the dependency injection that can not be solved.
injector introduces services to clients. Often, it also builds clients. Injectors can connect a very complex object graph by treating objects like clients and then as services to other clients. Injectors may actually be many objects that work together but may not be clients. Injector can be referred with another name such as: assembler, provider, container, factory, builder, spring, construction code, or main.
Dependency injection can be applied as a discipline, requiring that all objects separate construction and behavior. Relying on the DI framework for doing construction may lead to prohibiting the use of new keywords , or, less strictly, only allowing the immediate construction of value objects.
Taxonomy
Inversion of control (IoC) is more common than DI. Simply put, IoC means letting other code call you instead of insisting on a call. IoC example without DI is template method pattern. Here, polymorphism is achieved through subclassing, that is, inheritance.
The injection dependency implements IoC through the composition so it is often identical to the strategy pattern, but while the strategy pattern is intended for dependencies that can be exchanged over the life of the object, in dependency injection may be just one instance of the dependencies used. It still reaches polymorphism, but through delegation and composition.
Dependency dependency framework
Application frameworks such as CDI and its implementation Weld, Spring, Guice, Play framework, Salta, Glassfish HK2, Dagger, and Managed Extensibility Framework (MEF) support dependency injection but are not required to perform dependency injection.
Benefits
- The dependency injection allows clients configurable flexibility. Only client behavior is corrected. The client can act on anything that supports the client's intrinsic interface.
- The dependency injection can be used to externalize the system configuration details into a configuration file, allowing the system to be reconfigured without recompiling. Separate configurations can be written for different situations that require different component implementations. This includes, but is not limited to, testing.
- Since dependency injection does not require changes in code behavior, it can be applied to legacy code as refactoring. The result is a more independent client and it is easier to unit test in isolation using stubs or artificial objects that simulate other untested objects. The ease of testing is often the first known benefit when using dependency injection.
- The dependency injection allows the client to remove all knowledge about the concrete implementation that needs to be used. This helps isolate clients from the impact of design changes and defects. It promotes reusability, testability and maintainability.
- Reduction of boilerplate code in the application object, because all work to initialize or manage dependencies is handled by the provider component.
- The dependency injection allows concurrent or independent development. Two developers can independently develop classes that use each other, while only need to know which class interface will communicate through. Plugins are often developed by third-party stores that never even talk to developers who create products that use plugins.
- Dependency injection reduces the merging of classes and their dependencies.
Losses
- The dependency injection creates a client requesting the configuration details provided by the construction code. This can be burdensome when a clear default is available.
- Dependency injection can make the code difficult to trace (read) because it separates the behavior of the constructs. This means the developer should refer to more files to follow how the system works.
- Dependency injection usually requires more initial development effort because one can not call into something right when and where it is needed but should request that it be injected and then ensure that it has been injected.
- The dependence of the force of the injection force to break out of the classroom and into inter-class relationships that may not always be desirable or easily managed. â ⬠<â ⬠<
- Dependency injection may induce dependence on the dependency injection framework.
Structure
UML class and sequence diagram
In the above UML class diagram, the Client
class that requires ServiceA
and ServiceB
objects does not provide an example ServiceA1
and < code> ServiceB1 class directly. Instead, the Injector
class creates the object and injects it into Client
, which makes Client
independent of how the object is created (the concrete class is used) The UML sequence diagram shows run-time interactions: The Injector
object creates the ServiceB1
objects. After that, Injector
creates the Client
object and injects ServiceB1
objects.
Example
Without dependency injection
In the following Java example, the Client class contains the member service variables initialized by the Client constructor. The client controls which service implementation is used and controls its construction. In this situation, the client is said to have a hard-code dependency on the ExampleService.
Dependency injection is an alternative technique to initialize member variables rather than explicitly creating service objects as shown above.
Three types of dependency injection
There are at least three ways an object can accept a reference to an external module:
- constructor injection : dependencies are provided through the class constructor.
- setter injection : the client exposes the setter method used by the injector to inject the dependency.
- injection interface : The dependency provides an injector method that will inject dependency to every client that is passed to it. The client must implement an interface that exposes a setter method that accepts a dependency.
Other types
It is possible for the DI framework to have other types of injection beyond those presented above.
The test framework can also use other types. Some modern testing frameworks do not even require clients to actively accept dependency injection so that inheritance code can be tested. In particular, in the Java language it is possible to use reflection to make private attributes public when tested and thus receive injections through assignment.
Some of the Inversion of Control attempts do not provide the removal of full dependence but only replace one form of dependency with another. As a rule of thumb, if a programmer can not see anything other than the client code and say what framework is being used, then the client has a hard-code dependency on the framework.
Constructor injection
This method requires the client to provide parameters in the constructor for the dependency.
Setter injection
This method requires the client to provide a setter method for dependency.
Interface injection
This is simply the client that publishes the role interface to the setter method of the client dependencies. This can be used to specify how the injector should talk to the client when injecting the dependencies.
Benchmark constructor constructor
It is preferable when all dependencies can be built first because it can be used to ensure the client object is always in a valid state, as opposed to some dependency reference being null (unmanageable). However, by itself, it lacks the flexibility to change its dependencies later on. This can be the first step to keep clients unchanged and therefore safe.
Setter injection comparison
Requires the client to provide a setter method for each dependency. It provides the freedom to manipulate the state of dependency reference at any time. It offers flexibility, but if there is more than one dependency to inject, it is difficult for the client to ensure that all dependencies are injected before the client can be provided for use.
Because these injections happen independently there is no way to know when the injector has finished wiring the client. Dependency can be left empty only with injectors that fail to call the tuner. This forces an inquiry that the injection has been completed from the time the client is assembled to whenever it is used.
Comparison of interface injection
The advantage of an injection interface is that dependencies can completely ignore their clients but can still receive references to new clients and, using them, send a self-reference back to the client. In this way, the dependence becomes the injector. The key is that the injection method (which could have been the classic setter method) is provided through the interface.
An assembler is still needed to introduce the client and its dependencies. The assembler takes a reference to the client, transmits it to the setter interface that specifies that dependency, and passes it to a dependent object that will reverse and return a reference to itself to the client.
For interface injection to have value, the dependency must do something other than simply return a reference to itself. It could act as a factory or sub-assembler to resolve other dependencies, thus abstracting some details from the main assembler. It could be a reference-count so that the dependence knows how many clients are using it. If the dependency maintains the collection of clients, it could then inject them all with different instances of itself.
Assemble the example
Manually assembling manually by hand is one way of applying dependency injection.
The above example manually graphs the object and then calls it at a point to start functioning. It is important to note that this injector is not pure. It uses one of the objects it constructs. It has only pure connection constructs with ExampleService but mixes construction and Client usage. This should not be common. However, it can not be avoided. Just as object-oriented software requires non-object-oriented static methods like main () to start, the object graph that is injected dependency requires at least one (preferably only one) entry point to get the usage started.
Manual construction in the main method may not be straight forward and may involve call builders, factories, or other construction patterns as well. It can be very advanced and abstract. This line is crossed from the manual dependency injection to the dependency injection framework after the build code is no longer custom to the application and not universal.
A framework such as Spring can build this same object and connect it together before returning a reference to the client. All mention of the Concrete Example Service can be moved from code to configuration data.
A framework such as Spring allows assembly details to be externalized in a configuration file. This code (above) creates the object and connects it together according to Beans.xml (below). ExampleService is still built even if only mentioned below. Graphs of long and complex objects can be defined in this way and the only class mentioned in the code will be one with the entry point method, which in this case is salam ().
In the example above, the Client and the Service do not have to undergo any changes provided by spring. They are allowed to remain a simple POJO. This shows how springs can connect services and clients who are completely unaware of their existence. This can not be said if spring annotations are added to the class. By storing spring-specific annotations and calls from spreading among many classes, the system remains dependent only on spring. This can be important if the system intends to live longer in spring.
The option to keep pure POJO does not come without cost. Instead of spending effort on developing and maintaining complex configuration files it is possible to only use annotations to mark classes and let the springs do the rest of the work. Resolving dependencies can be simple if they follow conventions like matching by type or name. This is choosing a convention over configuration. It is also arguable that, when refactoring to other frameworks, deleting a specific annotation framework would be a trivial part of the task and many standard injection annotations are now standardized.
Comparison of assembly
Different injector implementations (factory, service seeker, and dependency injection container) are not much different from dependency injection. What makes all the difference is where they are allowed to use. Moving a call to a factory or service seeker from the client and to the main and suddenly major makes the container injection dependency pretty good.
By transferring all knowledge of injectors, clean clients, free from the knowledge of the outside world, are left behind. However, any object that uses other objects may be considered a client. Objects containing the main are no exception. This main object does not use dependency injection. This actually uses the service locator pattern. This can not be avoided because the choice of service implementation should be made somewhere.
Externalizing the dependencies into the configuration file does not change this fact. What makes this reality part of a good design is that the service seekers are not scattered across the code base. It's limited to one place per app. This leaves the rest of the code base free to use dependency injection to create a clean client.
AngularJS Example
Within the AngularJS framework, there are only three ways a component (object or function) can directly access its dependencies:
- Components can create dependencies, typically using the
new
operator. - Components can look for dependencies, with reference to global variables.
- Components can have dependencies forwarded to where needed.
The first two options for creating or finding dependencies are not optimal because they replace them with dependencies on the components. This makes it difficult, if not impossible, to modify dependencies. This is especially problematic in tests, where it is often desirable to provide artificial dependencies for test isolation.
The third option is the most feasible, as it eliminates the responsibility for finding the dependency of the component. Dependency is only left to component.
In the example above SomeClass
is not related to creating or finding reliance dependents, it is only submitted to the greeter when it is used.
This is desirable, but it places the responsibility of getting dependency on the code that builds SomeClass
.
To manage dependency creation responsibilities, each AngularJS application has an injector. Injector is a service seeker responsible for construction and looking for dependency.
Here is an example of using injector services:
Create a new injector that can provide the components specified in the myModule
module and request a welcome service from the injector. (This is usually done automatically by AngularJS bootstrap).
Requesting a dependency solves the hard coding problem, but it also means that the injector should be passed to the entire application. Passing the injector violates the Law of Demeter. To correct this, we use declarative notation in our HTML templates, to assign the responsibility of making components to the injector, as in this example:
When AngularJS compiles HTML, it processes the ng-controller
command, which in turn asks the injector to create instances of the controller and its dependencies.
injector.instantiate (MyController);
This is all done behind the scenes. Since ng-controller
rejects the injector for instantiating the class, it can fulfill all MyController
dependencies without any controllers ever knowing about injectors. The application code only states the required dependencies, without having to deal with the injector. This setting does not violate Demeter's Law.
See also
- Architectural description language
- Factory pattern
- Inversion control
- Plug-in (computing)
- Pattern strategy
- AngularJS
- Service allocation pattern
- Parametrization
References
External links
- The composition of Root by Mark Seemann
- Beginner's Guide to Addiction Injection
- Injection & amp; Dependency Testable Objects: Designing loosely coupled and testable objects - Jeremy Weiskotten; Dr. Dobb's Journal, May 2006.
- Design Pattern: Addiction Injection - MSDN Magazine, September 2005
- Martin Fowler's original article introducing the term Addiction Injection
- P from EAA: Plugin
- The Rich Engineering Heritage Behind Dependency Injection - Andrew McVeigh - A detailed history of dependency injection.
- What is Injection Dependency? - Alternative explanation - Jakob Jenkov
- Write More Code Can Be Tested with Dependency Injection - Developer.com, October 2006
- Summary of Managed Extensions Framework - MSDN
- Ancient Description of the Dependency Mechanism by Hunt 1998
- Refactor Your Way to Dependency Injection Container
- Container Injection Containers are Code Pollutants
- Understanding IN in PHP
- You Do Not Need a Container Injection Container
Source of the article : Wikipedia