Данная статья является первой частью серии статей, предназначенных, по словам автора, для тех, кто не может разобраться с внедрением зависимостей и фреймворком Dagger 2, либо только собирается это сделать. Оригинал написан 18 ноября 2017 года. Изображения и GIF — из оригинала. Перевод вольный.
Dagger 2 — это полностью статический фреймворк для внедрения зависимостей в Java и Android, работающий во время компиляции. Dagger 2 — это адаптация созданного ранее компанией Square фреймворка Dagger, поддерживаемая компанией Google.
Если вы начинающий Android разработчик, изучающий непосредственно Android и параллельно получающий знания по Java, то данная статья для вас. Если вы пытались изучать Dagger 2 и то, что вы находили в интернете казалось вам немного сложным — не беспокойтесь, я тоже прошел через это (все мы немного особенные, каждому требуется свой подход в объяснении чего-либо) и эта статья определенно для вас. Если вы уже знакомы с внедрением зависимостей и Dagger, то вы сможете узнать что-нибудь новое или прояснить для себя некоторые вещи.
Предполагается, что вы уже знакомы с языком программирования Java, принципами ООП и Android разработкой.
Замечание: для объяснения данной концепции я буду использовать аналогии с телесериалом «Игра престолов». Если вы не знакомы с данным сериалом, то можете заменять имена классов на более удобные для вас. И вы должны обязательно начать смотреть этот сериал.
Понимание зависимостей и связей — это первый шаг для более четкого понимания концепций объектно-ориентированного программирования. Итак, что такое зависимость? Например, у нас есть класс
Это означает, что класс
Два класса, использующие друг друга называются связанными (‘coupled’). Связь между классами может быть либо сильной (‘tight’), либо слабой (‘loose’). Зависимости всегда направлены, то есть класс
Большое количество зависимостей в классе приводит к проблемам сильных связей (hard dependency), что плохо по следующим причинам:
Когда классы и методы слабо связаны, не связаны или не зависят от множества других — возможности повторного использования кода возрастают. Повторное использование кода — одна из базовых идей объектно-ориентированного программирования.
Для тестирования вы можете подменить (mock) конкретные объекты. Но если в классе или методе множество зависимостей, то тестировать его будет сложно. Если Java класс (например,
Когда код не может быть корректно протестирован, его части невозможно или сложно повторно использовать, а проект продолжает расти, тогда проект становится очень сложно поддерживать. Поддерживаемость зависит от множества других факторов, но пока новые разработчики в вашей команде понимают систему и делают работу коллег комфортнее, то ваш проект всё ещё поддерживаемый.
Есть множество типов зависимостей, но можно выделить основные:
Мы рассматривали пример зависимости от класса ранее. Конструктор класса
Метод
Следующий метод принимает объект
Позвольте мне отвлечься на другой пример. Класс
Если Java класс создаёт экземпляр другого класса через оператор
Зависимости плохи тем, что уменьшают возможности повторного использования кода, а также усложняют процесс тестирования, из-за чего поддерживать проект становится сложнее.
Зависимости могут быть различных типов: классовые, интерфейсные, от методов, от полей, прямые, косвенные и другие.
В следующей статье мы поговорим о решении проблем сильных связей (hard dependency), и да, вы правы, через внедрение зависимостей. Рассмотрим реальный пример, найдем сильную связь и проанализируем её.
Dagger 2 — это полностью статический фреймворк для внедрения зависимостей в Java и Android, работающий во время компиляции. Dagger 2 — это адаптация созданного ранее компанией Square фреймворка Dagger, поддерживаемая компанией Google.
Для кого эта статья?
Если вы начинающий Android разработчик, изучающий непосредственно Android и параллельно получающий знания по Java, то данная статья для вас. Если вы пытались изучать Dagger 2 и то, что вы находили в интернете казалось вам немного сложным — не беспокойтесь, я тоже прошел через это (все мы немного особенные, каждому требуется свой подход в объяснении чего-либо) и эта статья определенно для вас. Если вы уже знакомы с внедрением зависимостей и Dagger, то вы сможете узнать что-нибудь новое или прояснить для себя некоторые вещи.
Серия статей
- Dagger 2 для начинающих Android разработчиков. Введение (вы здесь).
- Dagger 2 для начинающих Android разработчиков. Внедрение зависимостей. Часть 1.
- Dagger 2 для начинающих Android разработчиков. Внедрение зависимостей. Часть 2.
- Dagger 2 для начинающих Android разработчиков. Dagger 2. Часть 1.
- Dagger 2 для начинающих Android разработчиков. Dagger 2. Часть 2.
- Dagger 2 для начинающих Android разработчиков. Dagger 2. Продвинутый уровень.
Часть 1. - Dagger 2 для начинающих Android разработчиков. Dagger 2. Продвинутый уровень.
Часть 2.
Требования
Предполагается, что вы уже знакомы с языком программирования Java, принципами ООП и Android разработкой.
Что такое зависимость?
Замечание: для объяснения данной концепции я буду использовать аналогии с телесериалом «Игра престолов». Если вы не знакомы с данным сериалом, то можете заменять имена классов на более удобные для вас. И вы должны обязательно начать смотреть этот сериал.
Понимание зависимостей и связей — это первый шаг для более четкого понимания концепций объектно-ориентированного программирования. Итак, что такое зависимость? Например, у нас есть класс
Targaryens
, использующий внутри себя другой класс или интерфейс, который называется Dragons
. Значит класс Targaryens
зависит от класса или интерфейса Dragons
.
GIF
Это означает, что класс
Targaryens
не может работать без Dragons
. Также это значит, что везде, где будет использоваться класс Targaryens
будет присутствовать класс Dragons
, то есть мы не сможем повторно использовать Targaryens
без повторного использования Dragons
. В этом случае Targaryens
— зависимый класс, а Dragons
— это зависимость. Зависимый зависит от своих зависимостей.Два класса, использующие друг друга называются связанными (‘coupled’). Связь между классами может быть либо сильной (‘tight’), либо слабой (‘loose’). Зависимости всегда направлены, то есть класс
Targaryens
зависит от Dragons
, но класс Dragons
может и не зависеть от класса Targaryens
.class Targaryens {
public Targaryens() {
//Каждый раз, когда мы используем Targaryens, нам необходимо создать экземпляр Dragons
Dragons dragons = new Dragons();
dragons.callForWar();
}
}
Чем плохи зависимости?
Большое количество зависимостей в классе приводит к проблемам сильных связей (hard dependency), что плохо по следующим причинам:
- Уменьшаются возможности повторного использования кода.
- Усложняется процесс тестирования.
- Ухудшается поддерживаемость (maintainability) кода при росте проекта.
#Повторное использование (reusablility)
Когда классы и методы слабо связаны, не связаны или не зависят от множества других — возможности повторного использования кода возрастают. Повторное использование кода — одна из базовых идей объектно-ориентированного программирования.
#Тестирование
Для тестирования вы можете подменить (mock) конкретные объекты. Но если в классе или методе множество зависимостей, то тестировать его будет сложно. Если Java класс (например,
Targaryens
) создаёт экземпляр другого класса (Dragons
) через оператор new
, то этот класс (Targaryens
) невозможно будет протестировать независимо от класса, который создан через оператор new
(Dragons
).#Поддерживаемость (maintainability)
Когда код не может быть корректно протестирован, его части невозможно или сложно повторно использовать, а проект продолжает расти, тогда проект становится очень сложно поддерживать. Поддерживаемость зависит от множества других факторов, но пока новые разработчики в вашей команде понимают систему и делают работу коллег комфортнее, то ваш проект всё ещё поддерживаемый.
Типы зависимостей
Есть множество типов зависимостей, но можно выделить основные:
- Зависимость от классов.
- Зависимость от интерфейсов.
- Зависимость от методов или полей.
- Прямая и косвенная зависимость.
#Зависимость от классов
Мы рассматривали пример зависимости от класса ранее. Конструктор класса
Targaryens
зависит или нуждается в классе Dragons
для вызова метода callForWar()
.#Зависимость от интерфейсов
Метод
executePlan
принимает интерфейс WarStrategy
как зависимость. WarStrategy
может быть реализован всеми домами (Targaryens, Starks, Lannisters и так далее).public Result executePlan(WarStrategy strategy) {
//WarStrategy реализуется всеми домами
}
#Зависимость от методов или полей
Следующий метод принимает объект
HouseClass
, а вызываемый им метод getKing()
является зависимостью, которую невозможно идентифицировать в сигнатуре метода.public String extractName(HouseClass house) {
return house.getKing();
//возвращает имя короля конкретного дома
}
#Прямые и косвенные зависимости
Позвольте мне отвлечься на другой пример. Класс
Targaryens
зависит от класса Starks
в завоевании трона. Но Starks
зависят от других королевств севера, например, Mormont
. Итак, получается, что Targaryens
напрямую зависят от Starks
и косвенно от Mormont
.Резюме
Если Java класс создаёт экземпляр другого класса через оператор
new
, то этот класс невозможно будет использовать или протестировать независимо от класса, который создан через оператор new
. Это называется зависимостью.Зависимости плохи тем, что уменьшают возможности повторного использования кода, а также усложняют процесс тестирования, из-за чего поддерживать проект становится сложнее.
Зависимости могут быть различных типов: классовые, интерфейсные, от методов, от полей, прямые, косвенные и другие.
Что дальше?
В следующей статье мы поговорим о решении проблем сильных связей (hard dependency), и да, вы правы, через внедрение зависимостей. Рассмотрим реальный пример, найдем сильную связь и проанализируем её.