Clean architecture android kotlin example

Clean Architecture с Kotlin

Apr 20, 2019 · 4 min read

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

Причина заключается в том, что код тесно связан с модулем данных ответа. Использование Чистой архитектуры (Clean architecture) помогает решить эту проблему. Это лучшее решение для крупных приложений с большим количеством функций и SOLID-принципами. Она была предложена Робертом С. Мартином (известным как Дядя Боб) в блоге “Чистый код” в 2012 году.

Зачем нужен чистый подход?

  1. Разделение кода на разные слои с назначенными обязанностями облегчает дальнейшую модификацию
  2. Высокий уровень абстракции
  3. Слабая связанность между частями кода
  4. Легкость тестирования кода

“Чистый код всегда выглядит так, будто написан с заботой.”

Какие бывают слои?

Domain-слой: Запускает независимую от других уровней бизнес-логику. Представляет собой чистый пакет kotlin без android-зависимостей.

Data-слой : Отправляет необходимые для приложения данные в domain-слой, реализуя предоставляемый доменом интерфейс.

Presentation-слой: Включает в себя как domain-, так и data-слои, а также является специфическим для android и выполняет UI-логику.

Что такое Domain-слой?

Базовый слой, соединяющий presentation-слой с data-слоем, в котором выполняется бизнес-логика приложения.

UseCases

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

Прецедент возвращает Flowable, который можно модифицировать в соответствии с требуемым наблюдателем. Есть два параметра. Т рансформер или ObservableTransformer, контролирующий выбор потока для выполнения логики, и репозиторий, который представляет собой интерфейс для data-слоя. Для передачи данных в data-слой используется HashMap.

Репозитории

Определяют функциональности в соответствии с требованиями прецедента, которые реализуются data-слоем.

Что такое Data-слой?

Этот слой предоставляет необходимые для приложения данные. Data-слой должен быть организован таким образом, чтобы данные могли быть использованы любым приложением без модификации логики представления.

API реализуют удаленную сеть. Он может включать любую сетевую библиотеку, такую как retrofit, volley и т. д. Аналогичным образом, DB реализует локальную базу данных.

В репозитории реализуются локальные, удаленные и любые другие источники данных. В примере выше класс NewsRepositoryImpl.kt реализует предоставляемый domain-слоем интерфейс. Он выступает в качестве единой точки доступа для data-слоя.

Что такое presentation-слой?

Presentation-слой реализует пользовательский интерфейс приложения. Этот слой выполняет только инструкции без какой-либо логики. Он внутренне реализует такие архитектуры, как MVC, MVP, MVVM, MVI и т. д. В этом слое соединяются все части архитектуры.

Папка DI обеспечивает внедрение всех зависимостей при запуске приложения, таких как сети, View Models, Прецеденты и т.д. DI в android реализуется с помощью dagger, kodein, koin или шаблона service locator. Все зависит от типа приложения. Я выбрал koin, поскольку его легче понять и реализовать, чем dagger.

Зачем использовать ViewModels?

В соответствии с документацией android, ViewModel:

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

Таким образом, ViewModel сохраняет данные при изменении конфигурации. Presenter в MVP привязан к представлению с интерфейсом, что усложняет тестирование, в то время как в ViewModel отсутствует интерфейс из-за архитектурно-ориентированных компонентов.

Читайте также:  Android 11 пасхалка samsung

Базовый View Model использует CompositeDisposable для добавления всех observables и удаляет их на стадии жизненного цикла @OnCleared.

Класс data wrapper используется в LiveData в качестве вспомогательного класса, который уведомляет представление о состоянии запроса (запуск, результат и т.д.).

Каким образом соединяются все слои?

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

Источник

Clean Architecture в Android для начинающих

Feb 17 · 7 min read

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

“Задача архитектуры программного обеспечения — минимизация человеческих ресурсов, необходимых для создания и обслуживания требуемой системы”

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

Теоретически обосновал достижение этих целей Robert Martin (он же Uncle Bob). Он написал три книги о применении «чистого» подхода при разработке программного обеспечения (ПО). Одна из этих книг называется «Чистая архитектура, профессиональное руководство по структуре и дизайну программного обеспечения (ПО )», она и явилась источником вдохновения при создании этой статьи.

Кто-то скажет, это так, но меня это не касается, ведь в моем приложении уже есть архитектура MVVM?

Что ж, возм о жно, Clean Architecture может показаться излишней в том случае, если вы работаете над простым проектом. Но как быть, если нужно разделить модули, протестировать их изолированно и помочь всей команде в работе над отдельными контейнерами кода? Подход Clean Architecture освобождает разработчиков от дотошного изучения программного кода, пытаясь понять функции и логику функционирования.

Немного теории

Вероятно, вы много раз видели эту послойную диаграмму. Правда, мне она не очень помогла понять, как преобразовать эти слои в подготовленном проекте Android. Но сначала разберемся с теорией и определениями:

· Сущности ( Entities): инкапсулируют наиболее важные правила функционирования корпоративного уровня. Сущности могут быть объектом с методами или набором из структур данных и функций.

· Сценарии использования ( Use cases): организуют поток данных к объектам и от них.

· Контроллеры, сетевые шлюзы, презентеры ( Controllers, Gateways, Presenters): все это набор адаптеров, которые наиболее удобным способом преобразуют данные из сценариев использования и формата объектов для передачи в верхний слой (обычно пользовательский интерфейс).

· UI, External Interfaces, DB, Web, Devices: самый внешний слой архитектуры, обычно состоящий из таких элементов, как пользовательские и внешние интерфейсы, базы данных и веб-фреймворки.

После прочтения этих определений я всегда оказывался в замешательстве и не был готов реализовать «чистый» подход в своих Android проектах.

Прагматичный подход

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

· Домен: содержит определения логики функционирования приложения, модели данных сервера, абстрактное определение репозиториев и определение сценариев использования. Это простой, чистый модуль kotlin (независимый от Android).

· Данные: содержит реализацию абстрактных определений доменного слоя. Может быть повторно использован любым приложением без модификаций. Он содержит репозитории и реализации источников данных, определение базы данных и ее DAO, определения сетевых API, некоторые средства преобразования для конвертации моделей сетевого API в модели базы данных и наоборот.

Читайте также:  Как пользоваться андроидом с другого андроида

· Приложение (или слой представления): он зависит от Android и содержит фрагменты, модели представления, адаптеры, действия и т.д. Он также содержит указатель служб для управления зависимостями, но при желании вы можете использовать Hilt.

Практическая часть — небольшое приложение для книжного каталога

Чтобы применить на практике все эти “абстрактные” понятия, я разработал простое приложение, которое демонстрирует список книг, написанных дядей Бобом, и которое дает пользователям возможность помечать некоторые из них как “избранные”.

Модуль домена

Чтобы получить список книг, я использовал API Google книги. Это API возвращает список книг, отфильтрованных по параметру строки запроса:

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

data class Volume(val id: String, val volumeInfo: VolumeInfo)

Простая сущность класса данных:

Абстрактное определение репозитария книг

Сценарии использования “Get books”

Модуль домена

Чтобы получить список книг, я использовал API Google книги. Это API возвращает список книг, отфильтрованных по параметру строки запроса:

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

Простой объект (entity) класса данных:

data class Volume(val id: String, val volumeInfo: VolumeInfo)

Абстрактное определение репозитария книг:

Сценарии использования “Get books”:

Слой данных

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

Поскольку мы определили источник данных для управления постоянством (persistence), на этом уровне нам также необходимо определить базу данных (можно использовать Room) и ее объекты. Кроме того, рекомендуется создать несколько модулей (mappers) для сопоставления ответа API с соответствующим объектом базы данных. Помните, нам нужно, чтобы доменный слой был независим от слоя данных, поэтому мы не можем напрямую аннотировать объект доменного тома ( Volume ) с помощью аннотации @Entity room . Нам определенно нужен еще один класс BookEntity , и мы определим маппер (mapper) между Volume и BookEntity .

Слой презентации или приложения

В этом слое нам нужен фрагмент для отображения списка книг. Мы можем сохранить наш любимый подход MVVM. Модель представления принимает сценарии использования в своих конструкторах и вызывает соответствующий сценарий использования соответственно действиям пользователя (get books, bookmark, unbookmark).

Каждый сценариё использования вызывает соответствующий метод в репозитории:

Этот фрагмент только наблюдает за изменениями в модели представления и обнаруживает действия пользователя в пользовательском интерфейсе:

Теперь посмотрим, как мы выполнили связь между слоями:

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

Источник

Clean Architecture с Kotlin

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

Причина заключается в том, что код тесно связан с модулем данных ответа. Использование Чистой архитектуры (Clean architecture) помогает решить эту проблему. Это лучшее решение для крупных приложений с большим количеством функций и SOLID-принципами. Она была предложена Робертом С. Мартином (известным как Дядя Боб) в блоге “Чистый код” в 2012 году.

Читайте также:  Android change language programmatically

Зачем нужен чистый подход?

  1. Разделение кода на разные слои с назначенными обязанностями облегчает дальнейшую модификацию
  2. Высокий уровень абстракции
  3. Слабая связанность между частями кода
  4. Легкость тестирования кода

“Чистый код всегда выглядит так, будто написан с заботой.” — Майкл Фэзерс

Какие бывают слои?

Domain-слой: Запускает независимую от других уровней бизнес-логику. Представляет собой чистый пакет kotlin без android-зависимостей.

Data-слой: Отправляет необходимые для приложения данные в domain-слой, реализуя предоставляемый доменом интерфейс.

Presentation-слой: Включает в себя как domain-, так и data-слои, а также является специфическим для android и выполняет UI-логику.

Что такое Domain-слой?

Базовый слой, соединяющий presentation-слой с data-слоем, в котором выполняется бизнес-логика приложения.

Структура domain-слоя приложения

UseCases

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

Прецедент возвращает Flowable, который можно модифицировать в соответствии с требуемым наблюдателем. Есть два параметра. Трансформер или ObservableTransformer, контролирующий выбор потока для выполнения логики, и репозиторий, который представляет собой интерфейс дляdata-слоя. Для передачи данных в data-слой используется HashMap.

Репозитории

Определяют функциональности в соответствии с требованиями прецедента, которые реализуются data-слоем.

Что такое Data-слой?

Этот слой предоставляет необходимые для приложения данные. Data-слой должен быть организован таким образом, чтобы данные могли быть использованы любым приложением без модификации логики представления.

Структура data-слоя приложения

API реализуют удаленную сеть. Он может включать любую сетевую библиотеку, такую как retrofit, volley и т. д. Аналогичным образом, DB реализует локальную базу данных.

В репозитории реализуются локальные, удаленные и любые другие источники данных. В примере выше класс NewsRepositoryImpl.kt реализует предоставляемый domain-слоем интерфейс. Он выступает в качестве единой точки доступа для data-слоя.

Что такое presentation-слой?

Presentation-слой реализует пользовательский интерфейс приложения. Этот слой выполняет только инструкции без какой-либо логики. Он внутренне реализует такие архитектуры, как MVC, MVP, MVVM, MVI и т. д. В этом слое соединяются все части архитектуры.

Структура presentation-слоя приложения

Папка DI обеспечивает внедрение всех зависимостей при запуске приложения, таких как сети, View Models, Прецеденты и т.д. DI в android реализуется с помощью dagger, kodein, koin или шаблона service locator. Все зависит от типа приложения. Я выбрал koin, поскольку его легче понять и реализовать, чем dagger.

Зачем использовать ViewModels?

В соответствии с документацией android, ViewModel:

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

Таким образом, ViewModel сохраняет данные при изменении конфигурации. Presenter в MVP привязан к представлению с интерфейсом, что усложняет тестирование, в то время как в ViewModel отсутствует интерфейс из-за архитектурно-ориентированных компонентов.

Базовый View Model использует CompositeDisposable для добавления всех observables и удаляет их на стадии жизненного цикла @OnCleared.

Класс data wrapper используется в LiveData в качестве вспомогательного класса, который уведомляет представление о состоянии запроса (запуск, результат и т.д.).

Каким образом соединяются все слои?

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

Application Flow

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

Источник

Оцените статью