#android #dependency-injection #dagger-2 #dagger #dagger-hilt
#Android #внедрение зависимостей #dagger-2 #dagger #dagger-рукоять
Вопрос:
Я изучаю DI с помощью Dagger2 и Hilt, и у меня возник вопрос: при создании приложения для Android я заметил, что использую множество служебных классов со статическими методами (т. Е. Функцию, Которая получает температуру в градусах Цельсия и возвращает ее в градусах Фаренгейта). НО также я использую класс (скажем, NetworkUtils) со статическим служебным методом для выполнения сетевого вызова для получения данных из API (как это делали преподаватели курса Android Nanodegree): то, что я делаю, похоже:
class NetworkUtils{
public static String fetchCityName(double latitude, double longitude){
// code for API call
}
}
И теперь, когда я изучаю принципы DI из документов разработчика, я замечаю, что сетевые вызовы выполняются в классе экземпляра в методе экземпляра, а его параметры вводятся с помощью Dagger.
- Почему это отличается от того, что я делал? Я читал, что статические методы затрудняют тестирование, однако предположим, что я использовал DI, как показано в документах,
- Почему я должен создавать экземпляр нового объекта NetworkUtils всякий раз, когда мне нужно выполнить вызов API, в то время как создание нескольких экземпляров бесполезно? Кроме того, в официальных документах говорится, что наше использование аннотации @Singleton для установки области действия функции (т. Е. Для функции вызова REST API) должно быть очень редким, тогда:
- Должен ли я создавать экземпляры для всего, что мне нужно использовать, даже если это не нужно? (за исключением дорогостоящего создания экземпляра объекта)
- В конце концов, не могли бы вы пояснить разницу между служебным классом и обычным классом, что я не должен использовать в нем статические методы?
Спасибо.
Комментарии:
1. Это очень широкий вопрос, и на него нет четкого ответа. Если класс не имеет состояния, то нет смысла вводить его, поскольку все экземпляры равны. [Я разумно ожидаю, что у такого класса, как NetworkUtils, будут некоторые поля, указывающие, какой серверный сервер вызывать и т. Д. Это может быть даже интерфейс, учитывая тот метод, который вы показываете здесь.]
Ответ №1:
И теперь, когда я изучаю принципы DI из документов разработчика, я замечаю, что сетевые вызовы выполняются в классе экземпляра в методе экземпляра, а его параметры вводятся с помощью Dagger.
- Почему это отличается от того, что я делал? Я читал, что статические методы затрудняют тестирование, однако предположим, что я использовал DI, как показано в документах,
Я вижу две основные причины:
Во-первых, конечно, статические вызовы затрудняют тестирование кода. Но да, есть некоторые тестовые фреймворки, которые могут выполнить всю работу за вас и имитировать статические вызовы. Но всякий раз, когда вы их используете, это, скорее всего, означает, что вы делаете что-то не так или работаете с устаревшим кодом. Это подводит меня ко второй теме.
Идея разработки, основанной на TDD-тестировании, заключается в том, что сначала вы пишете тесты, а затем код. Но тесты «не важны». На самом деле, реальный результат — лучший код! Модульный тест просто помогает, но они являются субпродуктами. В большинстве случаев существует высокая корреляция между хорошим кодом и тестируемым кодом. Когда у вас есть статические вызовы и одиночные вызовы, вам легко вызвать этот код из любого места, где вы хотите. В результате вы перестаете думать о дизайне, о реальных принципах ООП — что есть что. Вы не думаете о дополнительных объектах, связи между объектами и т. Д. И в итоге получается спагетти-код. Все привязано ко всему остальному.
- Почему я должен создавать экземпляр нового объекта NetworkUtils всякий раз, когда мне нужно выполнить вызов API, в то время как создание нескольких экземпляров бесполезно? Кроме того, в официальных документах говорится, что наше использование аннотации @Singleton для установки области действия функции (т. Е. Для функции вызова REST API) должно быть очень редким, тогда:
Вы говорите что-то противоречивое — «создание нескольких экземпляров бесполезно». Очевидно, что создание экземпляра, а не использование статического вызова, помогает вам улучшить и протестировать код. Возможно, вам интересно, влияет ли это на производительность. Здесь я процитирую.. может быть, Мартин Фаулер… но в своей книге о рефакторинге он объясняет, что в 9 из 10 оптимизаций просто бесполезны. Вы переусердствовали. Вам нужно написать хороший код. Затем оцените. Тогда, если есть необходимость в оптимизации — у вас есть хороший код — оптимизация будет относительно простой.
В вашем случае — не волнуйтесь. Сколько экземпляров вызовет перенос сетевых вызовов в классы экземпляров? 3? 5? Это не проблема, когда вы оцениваете преимущества.
О синглтоне — вам не нужно общее состояние — поэтому нет необходимости в синглтоне. Вы выстрелите себе в ногу. Вы сохраните вещи, которые могут быть собраны в мусор, добавите дополнительный код для создания одноэлементных элементов и т. Д. Просто обычный объект и все.
- Должен ли я создавать экземпляры для всего, что мне нужно использовать, даже если это не нужно? (за исключением дорогостоящего создания экземпляра объекта)
Это огромный вопрос. Вы должны прочитать несколько книг и все равно не будете знать ответа. Попробуйте использовать чистый код дяди Боба, а также рефакторинг Мартина Фаулера. Затем прочитайте несколько статей людей, которые считают, что они переусердствовали, и найдите баланс для себя. В общем, вы не должны использовать «новые» и любые статические вызовы.. Но, например, существует много дискуссий о том, насколько действительно полезны модульные тесты на Android, и есть много людей, которые склонны идти в том направлении, в котором вам нужны в основном интеграционные и сквозные тесты. Я не буду спорить, какой подход правильный.
4. Eventually, could you please clarify the difference between a utility class and a normal class that I should not use static methods in it?
В принципе, вы не должны использовать «Служебные классы». Их идея состоит в том, чтобы обернуть некоторый код, который используется во многих местах, но не задействовано состояние. Вам не нужны переменные экземпляра, поэтому статические методы были хорошей идеей. Но это полностью убьет ваше тестирование. Итак, в вашем случае вы должны создать один тип класса, и если вам нужно состояние — добавьте, если вам не нужно состояние — просто не делайте этого. Тогда вы можете называть классы как угодно.
Комментарии:
1. Я бы также рекомендовал книгу «Принципы, методы и шаблоны внедрения зависимостей» — manning.com/books /…