Внедрение зависимости (англ. Dependency injection, DI) — процесс предоставления внешней зависимости программному компоненту. Является специфичной формой «инверсии управления» (англ. Inversion of control, IoC), когда она применяется к управлению зависимостями. В полном соответствии с принципом единственной ответственности объект отдаёт заботу о построении требуемых ему зависимостей внешнему, специально предназначенному для этого общему механизму[1].
При настоящем внедрении зависимости объект пассивен и не предпринимает вообще никаких шагов для выяснения зависимостей, а предоставляет для этого сеттеры и/или принимает своим конструктором аргументы, посредством которых внедряются зависимости[1].
В этом разделе не хватает ссылок на источники информации. |
Работа фреймворка, обеспечивающая внедрение зависимости, описывается следующим образом. Приложение, независимо от оформления, исполняется внутри контейнера IoC, предоставляемого фреймворком. Часть объектов в программе по-прежнему создается обычным способом языка программирования, часть создается контейнером на основе предоставленной ему конфигурации.
Условно, если объекту нужно получить доступ к определенному сервису, объект берет на себя ответственность за доступ к этому сервису: он или получает прямую ссылку на местонахождение сервиса, или обращается к известному «сервис-локатору» и запрашивает ссылку на реализацию определенного типа сервиса. Используя же внедрение зависимости, объект просто предоставляет свойство, которое в состоянии хранить ссылку на нужный тип сервиса; и когда объект создается, ссылка на реализацию нужного типа сервиса автоматически вставляется в это свойство (поле), используя средства среды.
Внедрение зависимости более гибко, потому что становится легче создавать альтернативные реализации данного типа сервиса, а потом указывать, какая именно реализация должна быть использована в, например, конфигурационном файле, без изменений в объектах, которые этот сервис используют. Это особенно полезно в юнит-тестировании, потому что вставить реализацию «заглушки» сервиса в тестируемый объект очень просто.
С другой стороны, излишнее использование внедрения зависимостей может сделать приложения более сложными и трудными в сопровождении: так как для понимания поведения программы программисту необходимо смотреть не только в исходный код, а еще и в конфигурацию, а конфигурация, как правило, невидима для IDE, которые поддерживают анализ ссылок и рефакторинг, если явно не указана поддержка фреймворков с внедрениями зависимостей.
При использовании внедрения зависимостей, как правило, существует конфигурационный механизм или архитектура, которая определяет целесообразность выбора той или иной реализации в зависимости от поставленных целей.
1 <?php
2 /**
3 * Класс конфигурация базы данных
4 */
5 class DbConfiguration{
6
7 private $host;
8 private $port;
9 private $username;
10 private $password;
11
12 public function __construct(string $host, int $port, string $username, string $password){
13 // вся соль Di находится в строчках ниже
14 $this->host = $host;
15 $this->port = $port;
16 $this->username = $username;
17 $this->password = $password;
18 }
19
20 public function getHost(){
21 return $this->host;
22 }
23
24 public function getPort(){
25 return $this->port;
26 }
27
28 public function getUsername(){
29 return $this->username;
30 }
31
32 public function getPassword(){
33 return $this->password;
34 }
35 }
36
37 /**
38 * Класс соединение с базой данных
39 */
40 class DbConnection{
41
42 private $configuration;
43
44 public function __construct(DbConfiguration $config){
45 // вся соль Di находится в строчке ниже
46 $this->configuration = $config;
47 }
48
49 public function getDsn(){
50 // примечание: это не реальный dsn, разделители в реальном dsn другие
51 return sprintf(
52 '%s:%s@%s:%d',
53 $this->configuration->getUsername(),
54 $this->configuration->getPassword(),
55 $this->configuration->getHost(),
56 $this->configuration->getPort()
57 );
58 }
59 }
60
61 // создаем объект конфигурации базы данных, передав в конструктор параметры
62 $config = new DbConfiguration('localhost', 3306, 'username', 'password');
63 // создаем объект соединения с базой, передав в конструктор объект конфигурации
64 // использование Di дает слабосвязность кода
65 $connection = new DbConnection($config);
public interface ICar {
public float getSpeed();
public void setPedalPressure(final float PEDAL_PRESSURE);
}
public interface IEngine {
public float getEngineRotation();
public void setFuelConsumptionRate(final float FUEL_FLOW);
}
public class DefaultEngineImpl implements IEngine {
private float engineRotation = 0;
public float getEngineRotation() {
return engineRotation;
}
public void setFuelConsumptionRate(final float FUEL_FLOW) {
engineRotation = …;
}
}
public class DefaultCarImpl implements ICar {
private IEngine engine = new DefaultEngineImpl();
public float getSpeed() {
return engine.getEngineRotation()*…;
}
public void setPedalPressure(final float PEDAL_PRESSURE) {
engine.setFuelConsumptionRate(…);
}
}
public class MyApplication {
public static void main(String[] args) {
DefaultCarImpl car = new DefaultCarImpl();
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
public class DefaultCarImpl implements ICar {
private IEngine engine;
public DefaultCarImpl(final IEngine engineImpl) {
engine = engineImpl;
}
public float getSpeed() {
return engine.getEngineRotation()*…;
}
public void setPedalPressure(final float PEDAL_PRESSURE) {
engine.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();
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
<service-point id="CarBuilderService">
<invoke-factory>
<construct class="Car">
<service>DefaultCarImpl</service>
<service>DefaultEngineImpl</service>
</construct>
</invoke-factory>
</service-point>
/** Неявная реализация **/
public class MyApplication {
public static void main(String[] args) {
Service service = (Service)DependencyManager.get("CarBuilderService");
ICar car = (ICar)service.getService(Car.class);
car.setPedalPressure(5);
float speed = car.getSpeed();
System.out.println("Speed of the car is " + speed);
}
}
Для улучшения этой статьи желательно: |
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .