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

21
Управление зависимостями в программном коде (dependency injection & Inversion of Control includes)

Upload: dmitrey-naumenko

Post on 02-Jul-2015

3.409 views

Category:

Technology


4 download

TRANSCRIPT

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

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

(dependency injection &

Inversion of Control includes)

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

Agenda

• Качество архитектуры приложения• Что такое зависимый код?• Что такое инъекция зависимости?• Инверсия зависимости• IoC-контейнеры

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

Это вам знакомо?

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

• Методы и классы сложно повторно использовать

• Изменения идут «со скрипом». Трудно что-либо добавить или изменить.

• «Без пол литра не разобраться» или «покажите мне умника, который так пишет?»

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

Признаки плохой архитектуры

• Хрупкость (изменения ведут к поломкам)• Монолитность (сопротивление к

повторному использованию)• Жесткость (сопротивление к изменениям)• Чрезмерная сложность (ничего непонятно)• Вязкость («грязные» приемы работают

лучше: Copy-Paste, «Объект Бога», «Спагетти код» и т.д.)

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

Одна из причинСильное связывание кода (Tight Coupling)

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

Что такое зависимый код?

• public class User {

private MessageService transport = new SmtpMessageService();

public void sendMessage() {

transport.send();}

}

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

Зависимость!

• public class User {

private MessageService transport = new SmtpMessageService();

public void sendMessage() {

transport.send();}

}

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

Проблемы с классом User

• Мы не можем изменить реализацию MessageService

• Мы не можем протестировать класс User отдельно от класса SmtpMessageService

• Необходимо создавать новый класс или наследовать от класса User, чтобы добавить новую реализацию.

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

Как избавиться от зависимости?

• Передать объект через set-метод:public void setMessageService(MessagService messageService) {

this.messageService = messageService;

}

• Передать объект через конструктор:public User(MessageService transport) {

this.transport = transport;

}

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

Решение найденоИнъекция зависимости

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

Инъекция!

• Передать объект через set-метод:public void setMessageService(MessagService transport) {

this.transport = transport;

}

• Передать объект через конструктор:public User(MessageService transport) {

this.transport = transport;

}

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

}

}

Page 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”

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

Что это нам дает?

• Менее связанный код (low coupling)• Небольшие, сильно зацепленные классы

(high cohesion)• Возможность повторного использования

(reuse)• Расширяемость

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

Ответственность перешла другому классуИнверсия зависимости

Page 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”

Ответственность переходит классам верхнего уровня в соответствии принципом инверсии зависимости.

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

Принцип инверсии

• Зависимости внутри системы стоятся на основе абстракций (интерфейсы или абстрактные классы).

• Модули верхнего уровня не зависят от модулей нижнего уровня.

• Абстракции не зависят от подробностей.

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

IoC контейнеры

• IoC (Inversion of Control) контейнер – это специальный объект-сборщик, который на основании схемы зависимостей между классами и абстракциями может создать граф объектов. Любой IoC контейнер реализует принцип инверсии зависимостей

• IoC контейнеры появились в Java– Spring– Pico container

• IoC контейнеры используются на самых верхних уровнях приложений для инициализации объектов с учетом всех зависимостей

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

Java: Spring Framework

• Позиционируется как complete dependency injection tool

• Позволяет описывать зависимости в коде или через XML-файл

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

Пример для 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();

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

Хорошая архитектура

• Простота – чем меньше архитектурных решений, тем проще

• Очевидность использования – минимум движений, чтобы получить результат

• Расширяемость – когда есть требования, система легко вбирает в себя функционал

• Устойчивость – разделение ролей позволяет быстро локализировать ошибки

• Повторное использование – низкая зависимость определяет возможности по использованию