Управление зависимостями
   в программном коде
     (dependency injection &
   Inversion of Control includes)
Agenda
•   Качество архитектуры приложения
•   Что такое зависимый код?
•   Что такое инъекция зависимости?
•   Инверсия зависимости
•   IoC-контейнеры
Это вам знакомо?
• Изменения в одном месте приводят к
  поломкам в другом
• Методы и классы сложно повторно
  использовать
• Изменения идут «со скрипом». Трудно что-
  либо добавить или изменить.
• «Без пол литра не разобраться» или
  «покажите мне умника, который так
  пишет?»
Признаки плохой архитектуры
• Хрупкость (изменения ведут к поломкам)
• Монолитность (сопротивление к
  повторному использованию)
• Жесткость (сопротивление к изменениям)
• Чрезмерная сложность (ничего непонятно)
• Вязкость («грязные» приемы работают
  лучше: Copy-Paste, «Объект Бога»,
  «Спагетти код» и т.д.)
Одна из причин
Сильное связывание кода (Tight Coupling)
Что такое зависимый код?
• public class User {
     private MessageService transport = new
            SmtpMessageService();

      public void sendMessage() {
            transport.send();
      }
  }
Зависимость!
• public class User {
     private MessageService transport = new
            SmtpMessageService();

      public void sendMessage() {
            transport.send();
      }
  }
Проблемы с классом User
• Мы не можем изменить реализацию
  MessageService
• Мы не можем протестировать класс User
  отдельно от класса SmtpMessageService
• Необходимо создавать новый класс или
  наследовать от класса User, чтобы добавить
  новую реализацию.
Как избавиться от зависимости?
• Передать объект через set-метод:
        public void setMessageService(MessagService messageService) {
                 this.messageService = messageService;
        }

• Передать объект через конструктор:
    public User(MessageService transport) {
                this.transport = transport;
    }
Решение найдено
Инъекция зависимости
Инъекция!
• Передать объект через set-метод:
        public void setMessageService(MessagService transport) {
                 this.transport = transport;
        }

• Передать объект через конструктор:
    public User(MessageService transport) {
                this.transport = transport;
    }
Программирование основано на
             интерфейсах
•   public interface MessageService {
         public void send(String message);
    }
•   public class SmtpMessageService implements MessageService {
         public void send(String message) {
                   System.out.println(“Via smtp: ” + message);
         }
    }
•   public class JabberMessageService implements MessageService {
    public void send(String message) {
                   System.out.println(“Via jabber: ” + message);
         }
    }
Пример использования
•   User userWithSmtp = new User();
    userWithSmtp.setMessageService(new SmtpMessageService()) ;
    userWithSmtp.send(“you can do it”); // print “Via smtp: you can do it”

•   User userWithJabber= new User();
    userWithJabber.setMessageService(new SmtpMessageService()) ;
    userWithJabber.send(“ yes, you can”); // print “Via jabber: yes, you can”
Что это нам дает?
• Менее связанный код (low coupling)
• Небольшие, сильно зацепленные классы
  (high cohesion)
• Возможность повторного использования
  (reuse)
• Расширяемость
Ответственность перешла другому классу
Инверсия зависимости
Кто-то должен это делать
•   User userWithSmtp = new User();
    userWithSmtp.setMessageService(new SmtpMessageService()) ;
    userWithSmtp.send(“you can do it”); // print “Via smtp: you can do it”

•   User userWithJabber= new User();
    userWithJabber.setMessageService(new SmtpMessageService()) ;
    userWithJabber.send(“ yes, you can”); // print “Via jabber: yes, you can”




    Ответственность переходит классам верхнего уровня в соответствии
    принципом инверсии зависимости.
Принцип инверсии
• Зависимости внутри системы стоятся на
  основе абстракций (интерфейсы или
  абстрактные классы).
• Модули верхнего уровня не зависят от
  модулей нижнего уровня.
• Абстракции не зависят от подробностей.
IoC контейнеры
• IoC (Inversion of Control) контейнер – это специальный
  объект-сборщик, который на основании схемы
  зависимостей между классами и абстракциями может
  создать граф объектов. Любой IoC контейнер реализует
  принцип инверсии зависимостей
• IoC контейнеры появились в Java
   – Spring
   – Pico container
• IoC контейнеры используются на самых верхних уровнях
  приложений для инициализации объектов с учетом всех
  зависимостей
Java: Spring Framework
• Позиционируется как complete dependency
  injection tool
• Позволяет описывать зависимости в коде
  или через XML-файл
Пример для Spring Framework
• XML файл описания (dependency.xml)
<beans>
 <bean id=“messageService" class="com.my_app.StmpMessageService"/>
 <bean id="client" class="com.my_app.User">
  <property name=“transport">
   <ref bean="messageService"/>
  </property>
 </bean>
</beans>

• Получение объектов с учетом зависимостей
BeanFactory factory = new XmlBeanFactory(new
   FileInputStream("dependency.xml"));
User user= (User)factory.getBean(“user");
user.send();
Хорошая архитектура
• Простота – чем меньше архитектурных решений, тем
  проще
• Очевидность использования – минимум движений, чтобы
  получить результат
• Расширяемость – когда есть требования, система легко
  вбирает в себя функционал
• Устойчивость – разделение ролей позволяет быстро
  локализировать ошибки
• Повторное использование – низкая зависимость
  определяет возможности по использованию

Управление зависимостями в программном коде

  • 1.
    Управление зависимостями в программном коде (dependency injection & Inversion of Control includes)
  • 2.
    Agenda • Качество архитектуры приложения • Что такое зависимый код? • Что такое инъекция зависимости? • Инверсия зависимости • IoC-контейнеры
  • 3.
    Это вам знакомо? •Изменения в одном месте приводят к поломкам в другом • Методы и классы сложно повторно использовать • Изменения идут «со скрипом». Трудно что- либо добавить или изменить. • «Без пол литра не разобраться» или «покажите мне умника, который так пишет?»
  • 4.
    Признаки плохой архитектуры •Хрупкость (изменения ведут к поломкам) • Монолитность (сопротивление к повторному использованию) • Жесткость (сопротивление к изменениям) • Чрезмерная сложность (ничего непонятно) • Вязкость («грязные» приемы работают лучше: Copy-Paste, «Объект Бога», «Спагетти код» и т.д.)
  • 5.
    Одна из причин Сильноесвязывание кода (Tight Coupling)
  • 6.
    Что такое зависимыйкод? • public class User { private MessageService transport = new SmtpMessageService(); public void sendMessage() { transport.send(); } }
  • 7.
    Зависимость! • public classUser { private MessageService transport = new SmtpMessageService(); public void sendMessage() { transport.send(); } }
  • 8.
    Проблемы с классомUser • Мы не можем изменить реализацию MessageService • Мы не можем протестировать класс User отдельно от класса SmtpMessageService • Необходимо создавать новый класс или наследовать от класса User, чтобы добавить новую реализацию.
  • 9.
    Как избавиться отзависимости? • Передать объект через set-метод: public void setMessageService(MessagService messageService) { this.messageService = messageService; } • Передать объект через конструктор: public User(MessageService transport) { this.transport = transport; }
  • 10.
  • 11.
    Инъекция! • Передать объектчерез set-метод: public void setMessageService(MessagService transport) { this.transport = transport; } • Передать объект через конструктор: public User(MessageService transport) { this.transport = transport; }
  • 12.
    Программирование основано на интерфейсах • public interface MessageService { public void send(String message); } • public class SmtpMessageService implements MessageService { public void send(String message) { System.out.println(“Via smtp: ” + message); } } • public class JabberMessageService implements MessageService { public void send(String message) { System.out.println(“Via jabber: ” + message); } }
  • 13.
    Пример использования • User userWithSmtp = new User(); userWithSmtp.setMessageService(new SmtpMessageService()) ; userWithSmtp.send(“you can do it”); // print “Via smtp: you can do it” • User userWithJabber= new User(); userWithJabber.setMessageService(new SmtpMessageService()) ; userWithJabber.send(“ yes, you can”); // print “Via jabber: yes, you can”
  • 14.
    Что это намдает? • Менее связанный код (low coupling) • Небольшие, сильно зацепленные классы (high cohesion) • Возможность повторного использования (reuse) • Расширяемость
  • 15.
    Ответственность перешла другомуклассу Инверсия зависимости
  • 16.
    Кто-то должен этоделать • User userWithSmtp = new User(); userWithSmtp.setMessageService(new SmtpMessageService()) ; userWithSmtp.send(“you can do it”); // print “Via smtp: you can do it” • User userWithJabber= new User(); userWithJabber.setMessageService(new SmtpMessageService()) ; userWithJabber.send(“ yes, you can”); // print “Via jabber: yes, you can” Ответственность переходит классам верхнего уровня в соответствии принципом инверсии зависимости.
  • 17.
    Принцип инверсии • Зависимостивнутри системы стоятся на основе абстракций (интерфейсы или абстрактные классы). • Модули верхнего уровня не зависят от модулей нижнего уровня. • Абстракции не зависят от подробностей.
  • 18.
    IoC контейнеры • IoC(Inversion of Control) контейнер – это специальный объект-сборщик, который на основании схемы зависимостей между классами и абстракциями может создать граф объектов. Любой IoC контейнер реализует принцип инверсии зависимостей • IoC контейнеры появились в Java – Spring – Pico container • IoC контейнеры используются на самых верхних уровнях приложений для инициализации объектов с учетом всех зависимостей
  • 19.
    Java: Spring Framework •Позиционируется как complete dependency injection tool • Позволяет описывать зависимости в коде или через XML-файл
  • 20.
    Пример для SpringFramework • XML файл описания (dependency.xml) <beans> <bean id=“messageService" class="com.my_app.StmpMessageService"/> <bean id="client" class="com.my_app.User"> <property name=“transport"> <ref bean="messageService"/> </property> </bean> </beans> • Получение объектов с учетом зависимостей BeanFactory factory = new XmlBeanFactory(new FileInputStream("dependency.xml")); User user= (User)factory.getBean(“user"); user.send();
  • 21.
    Хорошая архитектура • Простота– чем меньше архитектурных решений, тем проще • Очевидность использования – минимум движений, чтобы получить результат • Расширяемость – когда есть требования, система легко вбирает в себя функционал • Устойчивость – разделение ролей позволяет быстро локализировать ошибки • Повторное использование – низкая зависимость определяет возможности по использованию