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

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

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

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

Содержание

Примеры кода

Представим, что IFoo это общий класс, определяющий свой интерфейс:

  class IFoo(Interface):
        def do_bar(self):
            "perform bar"
        def do_baz(self):
            "perform baz"

Также есть несколько реализаций, которые реализуют IFoo по-разному:

  class DatabaseFoo(object):
        interface.implements(IFoo)
        def do_bar(self):
            db.select_bar().execute() # Использовать базу данных, чтобы сделать bar
        def do_baz(self):
            db.select_baz().run() # Использовать базу данных, чтобы сделать baz
 
  class PixieDustFoo(object):
        interface.implements(IFoo)
        def do_bar(self):
            cast_spell("bar") # Магия...
        def do_baz(self):
            cast_spell("baz") # ...и волшебство
 
  class EnterpriseFoo(object):
        interface.implements(IFoo)
        def do_bar(self):
            bar = EnterpriseFactoryObserverFactoryCreator("bar")
            bar.creatify()
            bar.preparify()
            bar.configurise()
            bar.make_award_winning()
            bar.opportunities.leverage()
        def do_baz(self):
            baz = EnterpriseFactoryObserverFactoryCreator("baz")
            baz.creatify()
            baz.preparify()
            baz.configurise()
            baz.make_award_winning()
            baz.opportunities.leverage()

IFoo определяет только операции, которые доступны в интерфейсе, но не предоставляет никакой их реализации, позволяя другим классам реализовывать методы, в нем определенные (на то он и интерфейс). Поэтому пользователь, желающий использовать функционал IFoo, может использовать любую реализацию, не имея никакого понятия о том, как оно работает, кроме того, что они соответствуют спецификации интерфейса Foo.

  class ImportantClass(object):
        def __init__(self):
            self.foo = EnterpriseFoo()
        def do_really_important_stuff(self):
            self.foo.do_bar() # оно ничего не делает!

Хотя, это подрывает весь смысл использования интерфейсов вместо конечных реализаций. Чтобы исправить ситуацию, достаточно предоставить вызывающей стороне возможность указывать ту реализацию IFoo, которую она посчитает нужным:

        def __init__(self, foo):
            self.foo = foo

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

Пример кода на 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);
    }
}


Dependency injection вручную

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


Dependency injection при помощи фреймворка

    <service-point id="CarBuilderService">
        <invoke-factory>
            <construct class="Car">
                <service>DefaultCarImpl</service>
                <service>DefaultEngineImpl</service >
            </construct>
        </invoke-factory>
    </service-point>
/** Implementation not shown **/
 
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();
    }
}


Существующие фреймворки

Реализация внедрения зависимостей существует для различных платформ и языков, включая:

ActionScript

C++

ColdFusion

Java

.NET CF

.NET

Delphi

PHP4

PHP5

Perl

Python

Ruby

JavaScript

См. также

Внешние ссылки


Wikimedia Foundation. 2010.

Игры ⚽ Нужно решить контрольную?

Полезное


Смотреть что такое "Внедрение зависимости" в других словарях:

  • Внедрение SQL-кода — (англ. SQL injection)  один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL кода. Внедрение SQL, в зависимости от типа используемой СУБД и условий… …   Википедия

  • внедрение классификатора — Проведение комплекса мероприятий, обеспечивающих применение классификатора в предназначенной сфере деятельности. Общероссийские классификаторы в зависимости от их состава, содержания и назначения применяются в статистике, финансовой и банковской… …   Справочник технического переводчика

  • ВНЕДРЕНИЕ КЛАССИФИКАТОРА — проведение комплекса мероприятий, обеспечивающих применение классификатора в предназначенной сфере деятельности. Общероссийские классификаторы в зависимости от их состава, содержания и назначения применяются в статистике, финансовой и банковской… …   Большой бухгалтерский словарь

  • ВНЕДРЕНИЕ КЛАССИФИКАТОРА — проведение комплекса мероприятий, обеспечивающих применение классификатора в предназначенной сфере деятельности. Общероссийские классификаторы в зависимости от их состава, содержания и назначения применяются в статистике, финансовой и банковской… …   Большой экономический словарь

  • Инверсия управления — (Inversion of Control, IoC)  важный принцип объектно ориентированного программирования, используемый для уменьшения связанности в компьютерных программах. Формулировка: Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба …   Википедия

  • Spring Framework — У этого термина существуют и другие значения, см. Spring. Spring Framework Тип Application framework Разработчик SpringSource Написана на …   Википедия

  • Инъекция SQL — Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… …   Википедия

  • SQL-инъекция — Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… …   Википедия

  • SQL injection — Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… …   Википедия

  • SQL инъекция — Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… …   Википедия


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»