Injecție de dependență
Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de
versiunea revizuită pe 14 noiembrie 2019; verificările necesită
16 modificări .
Injecția de dependență (DI ) este procesul de furnizare a unei dependențe externe unei componente software . Este o formă specifică de „ inversie a controlului ” ( în engleză Inversion of control, IoC ) atunci când este aplicată managementului dependenței. În deplină concordanță cu principiul răspunderii unice, obiectul lasă grija construirii dependențelor de care are nevoie unui exterior, special conceput pentru acest mecanism general [1] .
Injecție de dependență reală
Când se folosește modelul „injectare de dependență”, obiectul este pasiv și nu face deloc pași pentru a determina dependențele, dar oferă setari pentru aceasta și/sau acceptă argumente în constructorul său prin care sunt injectate dependențe [1] .
Cum funcționează
Lucrarea cadrului de injectare a dependenței este descrisă după cum urmează. Aplicația, indiferent de design, rulează în interiorul containerului IoC oferit de cadru. Unele dintre obiectele din program sunt încă create în modul obișnuit al limbajului de programare, unele sunt create de container pe baza configurației furnizate acestuia.
Prin convenție, dacă un obiect trebuie să acceseze un anumit serviciu , obiectul își asumă responsabilitatea de a accesa acel serviciu: fie primește o referință directă la locația serviciului, fie merge la un „localizare de servicii” binecunoscut și solicită o referire la implementarea unui anumit tip de serviciu. Folosind injecția de dependență, un obiect pur și simplu expune o proprietate care este capabilă să stocheze o referință la tipul de serviciu dorit; iar când este creat un obiect, o referință la implementarea tipului de serviciu dorit este inserată automat în această proprietate (câmp) folosind instrumentele de mediu.
Injectarea dependenței este mai flexibilă deoarece devine mai ușor să se creeze implementări alternative ale unui anumit tip de serviciu și apoi să se specifice care implementare ar trebui utilizată, de exemplu, într- un fișier de configurare , fără a modifica obiectele care utilizează acel serviciu. Acest lucru este util în special în testarea unitară, deoarece este foarte ușor să inserați o implementare „ stub ” a serviciului în obiectul testat.
Pe de altă parte, utilizarea excesivă a injecției de dependență poate face aplicațiile mai complexe și mai dificil de întreținut: deoarece, pentru a înțelege comportamentul unui program, un programator trebuie să se uite nu numai la codul sursă, ci și la configurație, iar configurația este de obicei invizibilă pentru IDE , care acceptă analizarea și refactorizarea legăturilor, cu excepția cazului în care este specificat explicit pentru a suporta cadrele de injectare a dependențelor
.
Exemple de cod
Când se utilizează injecția de dependență, de regulă, există un mecanism sau o arhitectură de configurare care determină oportunitatea alegerii uneia sau alteia implementări, în funcție de obiective.
Exemple în diferite limbi
Exemplu de cod PHP
<?php
/**
* Clasa de configurare a bazei de date
*/
clasa DbConfiguration
{
private $gazdă ;
privat $port ;
privat $nume utilizator ;
private $parola ;
funcția publică __construct ( șir $gazdă , int $port , șir $nume utilizator , șir $parolă )
{
// întregul punct al lui Di este în liniile de mai jos
$acest -> gazdă = $gazdă ;
$acest -> port = $port ;
$this -> username = $username ;
$this -> parola = $parola ;
}
funcție publică getHost ()
{
returnează $this -> gazdă ;
}
funcție publică getPort ()
{
returneaza $this -> port ;
}
funcția publică getUsername ()
{
returnează $this -> nume de utilizator ;
}
funcția publică getPassword ()
{
returneaza $this -> parola ;
}
}
/**
* Clasa de conectare la baza de date
*/
clasa DbConnection
{
private $configurare ;
funcția publică __construct ( DbConfiguration $config )
{
// întreaga esență a lui Di este în linia de mai jos
$this -> configuration = $config ;
}
funcția publică getDsn ()
{
// notă: acesta nu este un dsn real, delimitatorii dsn reale sunt diferiți
întoarce sprintf (
„%s:%s@%s:%d” ,
$this -> configuration -> getUsername (),
$this -> configuration -> getPassword (),
$this -> configuration -> getHost (),
$this -> configuration -> getPort ()
);
}
}
// creează un obiect de configurare a bazei de date prin trecerea parametrilor către constructor
$config = new DbConfiguration ( 'localhost' , 3306 , 'username' , 'parola' );
// creăm un obiect de conexiune la baza de date prin trimiterea obiectului de configurare către constructor
// folosind Di face codul cuplat liber
$conexiune = new DbConnection ( $config );
Exemplu de cod Java
public interface ICar {
public float getSpeed ();
public void setPedalPressure ( plutitor final PEDAL_PRESSURE ); }
public interface IEngine {
public float getEngineRotation ();
public void setFuelConsumptionRate ( float final FUEL_FLOW ); }
Fără a utiliza injecția de dependență
public class DefaultEngineImpl implementează IEngine {
private float engineRotation = 0 ;
public float getEngineRotation () {
return engineRotation ;
}
public void setFuelConsumptionRate ( float final FUEL_FLOW ) { engineRotation = ... ; } }
public class DefaultCarImpl implementează ICar {
private IEngine engine = new DefaultEngineImpl ();
public float getSpeed () {
return engine . getEngineRotation () * ... ;
}
public void setPedalPressure ( final float PEDAL_PRESSURE ) {
motor . setFuelConsumptionRate ( ... );
}
}
public class MyApplication {
public static void main ( String [] args ) {
DefaultCarImpl car = new DefaultCarImpl ();
masina . setPedalPressure ( 5 );
viteză de plutire = mașină . getSpeed (); Sistem . afară . println ( "Viteza mașinii este " + viteza ); } }
Injecția manuală a dependenței
clasă publică DefaultCarImpl implementează ICar {
motor privat IEngine ;
public DefaultCarImpl ( final IEngine engineImpl ) {
engine = engineImpl ;
}
public float getSpeed () {
return engine . getEngineRotation () * ... ;
}
public void setPedalPressure ( final float PEDAL_PRESSURE ) {
motor . setFuelConsumptionRate ( ... );
}
}
public class CarFactory {
public static ICar buildCar () {
return new DefaultCarImpl ( new DefaultEngineImpl ());
}
}
public class MyApplication {
public static void main ( String [] args ) {
ICar car = CarFactory . buildCar ();
masina . setPedalPressure ( 5 );
viteză de plutire = mașină . getSpeed (); Sistem . afară . println ( "Viteza mașinii este " + viteza ); } }
Injecția de dependență cu un cadru
<service-point id= "CarBuilderService" >
<invoke-factory>
<construct class= "Car" >
<service> DefaultCarImpl
</service>
<service> DefaultEngineImpl
</service>
</construct>
</invoke-factory>
< /service-point>
/** Implementare implicită **/
public class MyApplication {
public static void main ( String [] args ) {
Service service = ( Service ) DependencyManager . obține ( "CarBuilderService" );
ICar car = ( ICar ) serviciu . getService ( Clasa auto ) ; masina . setPedalPressure ( 5 ); viteză de plutire = mașină . getSpeed (); Sistem . afară . println ( "Viteza mașinii este " + viteza ); } }
Vezi și
Note
- ↑ 12 Martin , 2008 .
Literatură
Link -uri