Показаны сообщения с ярлыком Управление зависимостями. Показать все сообщения
Показаны сообщения с ярлыком Управление зависимостями. Показать все сообщения

понедельник, 8 декабря 2014 г.

Для чего нужны интерфейсы?

В чем сила интерфейсов? Сила интерфейсов в правде слабости системы типов!

Принято считать, что интерфейсы предназначены для моделирования абстракций и обеспечения слабой связанности (loose coupling). Звучит умно, но что это значит?

Что дают интерфейсы?

Наследование моделирует семейство объектов с общим поведением. Интерфейс и абстрактный класс определяет «протокол» этого семейства, а наследники определяют конкретную реализацию. Разные виды предусловий можно спрятать за интерфейсом IPrecondition, разные виды стратегий сортировки – за ISorter, разные виды импортеров/экспортеров – за Importer/Exporter.

Наличие интерфейсов/абстрактных классов позволяет думать о задаче более абстрактно, не вдаваясь в подробности, какая конкретная разновидность используется. Абстрактность интерфейсов позволяет сосредоточиться на главном, игнорируя второстепенные детали. Отсюда вытекает распространенное убеждение, что интерфейс моделируют абстракцию.

четверг, 27 ноября 2014 г.

DI vs. DIP vs. IoC

Существует три схожих понятия, связанных передачей и управлением зависимостями, в каждом из которых есть слово “инверсия” (inversion) или “зависимость” (dependency):

  • IoC – Inversion of Control (Инверсия управления)
  • DI – Dependency Injection (Внедрение зависимостей)
  • DIP – Dependency Inversion Principle (Принцип инверсии зависимостей)

Подливает масло в огонь рассогласованность использования этих терминов. Так, например, контейнеры иногда называют DI-контейнерами, а иногда IoC-контейнерами. Большинство разработчиков не различает DI и DIP, хотя за каждой из этих аббревиатур скрываются разные понятия.

понедельник, 13 мая 2013 г.

Пример тестируемого дизайна

В комментариях к предыдущей заметке был задан такой вопрос:

«Вот есть, сккажем, класс, который читает какой-нибудь файл и потом его анализирует. Как такое тестировать?

Неужели надо вынести код чтения файла в отдельный класс, создать интерфейс и передать экземпляр через конструктор? Боюсь, если так буду делать, то не закончу и половины вовремя.»

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

пятница, 26 апреля 2013 г.

Тестируемый дизайн vs. хороший дизайн

DISCLAIMER: данную статью можно рассматривать, как дополнительные материалы к моему выступлению на MS SWIT с темой “Design for Testability: mocks, stubs, refactoring”.

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

В этой заметке я хочу показать типичный пример выделения интерфейсов для получения тестируемого дизайна и рассмотреть разницу между хорошим дизайном и тестируемым дизайном.

вторник, 9 апреля 2013 г.

Критический взгляд на принцип инверсии зависимостей

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

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) был впервые описан Бобом Мартином в одноименной статье, опубликованной в журнале C++ Report в 1996 году. Затем, практически в неизменном виде он был опубликован в книгах Боба Мартина «Принципы, паттерны и методики гибкой разработки» [Mattin2006].

По ходу статьи я буду приводить все необходимые цитаты и примеры из вышеупомянутых источников. Но чтобы не было «спойлеров» и ваше мнение оставалось объективным, я бы рекомендовал потратить 10-15 минут и ознакомиться с оригинальным описанием этого принципа в статье [Martin96] или книге [Martin96].

понедельник, 25 марта 2013 г.

DI Паттерны. Service Locator

Сервис локатор – это очень неоднозначный паттерн проектирования. С одной стороны, именно с его появлением началось активное развитие DI контейнеров и практик инверсии управления. С другой стороны, именно благодаря повсеместному использованию сервис локаторов в приложениях техники управления зависимостями получили и продолжают получать столько критики.

Но прежде чем переходить к описанию достоинств и недостатков этого паттерна, давайте дадим его описание и общую структуру.

четверг, 28 февраля 2013 г.

Аксиома управления зависимостями

Обсуждая практические аспекты управления зависимостями я говорил о том, что суть инверсии зависимостей заключается в том, что мы не хотим захламлять текущий класс лишними деталями, поэтому перекладываем их на более высокий уровень.

Интуитивно понятно, что в этом случае мы не избавляемся от зависимостей, а лишь перемещаем проблему из одного места в другое. Насколько этот подход разумен? Почему зависимости в одном месте влекут к проблемам сопровождаемости, а зависимости в другом месте безвредны?

вторник, 12 февраля 2013 г.

DI Паттерны. Method Injection

Сегодня мы переходим к самому простому паттерну передачи зависимостей – передаче через аргументы метода, Method Injection.

Существует две разновидности паттерна под названием Method Injection. В некоторых случаях под этим паттерном понимается установка зависимостей объекта с помощью вызова метода:

четверг, 7 февраля 2013 г.

О книге Марка Симана “Dependency Injection in .NET”

clip_image002

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

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

среда, 23 января 2013 г.

Инверсия зависимостей на практике

При обсуждении прошлой заметки в Г+ был задан вопрос о том, как избежать передачи самого контейнера в конкретные классы и ограничить распространение библиотеки управления зависимостями минимальным количеством мест. Я все равно думал раскрыть эту тему, а раз так, то почему бы не сделать этого сейчас.

Суть инверсии зависимостей сводится к тому, что класс перекладывает ответственность за создание зависимости или получение ее экземпляра на более высокий уровень, в результате чего, он сам не создает экземпляр конкретного класса, а получает его от более высокоуровневого кода через конструктор или свойство. В результате, мы заменяем композицию агрегацией и перекладываем часть проблем с текущего класса куда-то выше.

понедельник, 14 января 2013 г.

DI Паттерны. Property Injection

Возвращаемся к теме управления зависимостями, заброшенными  на некоторое время.

Еще одним достаточно популярным паттерном внедрения зависимостей является Property Injection, который заключается в передаче нужных зависимостей через “setter” свойства. Все современные DI-контейнеры в той или иной мере поддерживают этот паттерн, что делает его использование достаточно простым. Я рекомендую быть осторожным с этим паттерном, поскольку с точки дизайна передача зависимостей через свойства усложняет использование, понимание и поддержку.

Но давайте обо всем по порядку.

понедельник, 17 декабря 2012 г.

DI Паттерны. Constructor Injection

Когда речь заходит о внедрении зависимостей (Dependency Injection), то у большинства разработчиков в голове возникает образ конструктора, через который эта зависимость передается в виде интерфейса или абстрактного класса. Именно об этом виде управления зависимостей писал Боб Мартин в своей статье Dependency Inversion Principle, поэтому не удивительно, что он является самым известным.

Описание

Суть паттерна сводится к тому, что все зависимости, требуемые некоторому классу передаются ему в качестве параметров конструктора, представленных в виде интерфейсов или абстрактных классов.

понедельник, 3 декабря 2012 г.

Наследование vs Композиция vs Агрегация

Между двумя классами/объектами существует разные типы отношений. Самым базовым типом отношений является ассоциация (association), это означает, что два класса как-то связаны между собой, и мы пока не знаем точно, в чем эта связь выражена и собираемся уточнить ее в будущем. Обычно это отношение используется на ранних этапах дизайна, чтобы показать, что зависимость между классами существует, и двигаться дальше.

image

Рисунок 1. Отношение ассоциации

среда, 21 ноября 2012 г.

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

Приложите все усилия для того, чтобы вы управляли зависимостями в приложении, а не зависимости управляли вами.
Мнение автора статьи по поводу зависимостей

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

пятница, 26 октября 2012 г.

Фреймворки, библиотеки и зависимости

В одной из последних статей Ayende привел очень толковое определение разницы между библиотекой и фреймворком:

«Главное отличие библиотек от фреймворков в том, что фреймворк запускает ваш код, и, в общем случае, контролирует свое собственное окружение; в то время, как библиотека – это нечто, что вы используете из своего кода, контролируя свое окружение самостоятельно».

И это очень правильное определение. Фреймворк определяет окружение, используя «push» модель взаимодействия с приложением: в большинстве случаев фреймворк сам вызывает код приложения через механизм виртуальных методов, методы обратного вызова и т.п. Пользователю нужно лишь «вклинить» свой собственный код в «слоты», представленные фреймворком (не зря ведь в русскоязычном сообществе для термина “framework” используется «каркас»).