Внедрение зависимости

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Внедрение зависимости (англ. Dependency injection, DI) — процесс предоставления внешней зависимости программному компоненту. Является специфичной формой «инверсии управления» (англ. Inversion of control, IoC), где изменение порядка связи осуществляется путём получения необходимой зависимости.

Принцип работы[править | править вики-текст]

Работа фреймворка, обеспечивающая внедрение зависимости, описывается следующим образом. Приложение, независимо от оформления, исполняется внутри контейнера IoC, предоставляемого фреймворком. Часть объектов в программе по-прежнему создается обычным способом языка программирования, часть создается контейнером на основе предоставленной ему конфигурации.

Условно, если объекту нужно получить доступ к определенному сервису, объект берет на себя ответственность за доступ к этому сервису: он или получает прямую ссылку на местонахождение сервиса, или обращается к известному «сервис-локатору» и запрашивает ссылку на реализацию определенного типа сервиса. Используя же внедрение зависимости, объект просто предоставляет свойство, которое в состоянии хранить ссылку на нужный тип сервиса; и когда объект создается, ссылка на реализацию нужного типа сервиса автоматически вставляется в это свойство (поле), используя средства среды.

Внедрение зависимости более гибко, потому что становится легче создавать альтернативные реализации данного типа сервиса, а потом указывать, какая именно реализация должна быть использована в, например, конфигурационном файле, без изменений в объектах, которые этот сервис используют. Это особенно полезно в юнит-тестировании, потому что вставить реализацию «заглушки» сервиса в тестируемый объект очень просто.

С другой стороны, излишнее использование внедрения зависимостей может сделать приложения более сложными и трудными в сопровождении: так как для понимания поведения программы программисту необходимо смотреть не только в исходный код, а еще и в конфигурацию, а конфигурация, как правило, невидима для IDE, которые поддерживают анализ ссылок и рефакторинг, если явно не указана поддержка фреймворков с внедрениями зависимостей.

Примеры кода[править | править вики-текст]

При использовании внедрения зависимостей, как правило, существует конфигурационный механизм или архитектура, которая определяет целесообразность выбора той или иной реализации в зависимости от поставленных целей.

Пример кода на Java[править | править вики-текст]

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);
}

Без использования dependency injection[править | править вики-текст]

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)
    {
        ICar 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();
    }
}

См. также[править | править вики-текст]

Литература[править | править вики-текст]

Ссылки[править | править вики-текст]