Как выбрать подходящую архитектуру iOS (часть 2)

MVC, MVP, MVVM, VIPER или VIP

Вы можете ознакомиться с первой частью здесь.

Основные архитектуры iOS

Краткий обзор.

MVC

Уровни MVC следующие:

M: бизнес-логика, сетевой уровень и уровень доступа к данным

V: UI Layer (UIKit вещи, раскадровки, Xibs)

C: координирует посредничество между моделью и представлением.

Чтобы понять MVC, мы должны понимать контекст, в котором он был изобретен. MVC был изобретен в старые времена веб-разработки, когда Views не имеет состояния. В старые времена каждый раз, когда нам нужно визуальное изменение веб-сайта, браузер снова загружает весь HTML-код. В то время не было концепции сохранения и сохранения состояния представления.

Например, некоторые разработчики смешивали один и тот же HTML-файл, PHP и доступ к базе данных. Поэтому основной мотивацией MVC было отделение слоя View от слоя Model. Это увеличило тестируемость слоя модели. Предположительно в MVC слой View и Model не должен ничего знать друг о друге. Чтобы сделать это возможным, был изобретен промежуточный уровень с именем Controller. Это был SRP, который был применен.

Пример цикла MVC:

  1. Действие / событие пользователя на уровне просмотра (например, Обновить действие) запускается, и это действие передается в контроллер
  2. Контроллер, который запрашивает данные на уровне модели
  3. Смоделируйте возвращаемые данные в контроллер
  4. Контроллер говорит для просмотра обновить его состояние с новыми данными
  5. Посмотреть обновление своего состояния

Apple MVC

В iOS View Controller связан с UIKit и представлением жизненного цикла, так что это не чистый MVC. Однако в определении MVC нечего сказать, что Контроллер не может знать реализацию, специфичную для представления или модели. Его главная цель - отделить обязанности от слоя Model от слоя View, чтобы мы могли повторно использовать его и тестировать слой Model изолированно.

ViewController содержит представление и владеет моделью. Проблема в том, что мы использовали для написания кода контроллера, а также кода представления в ViewController.

MVC часто создает проблему Massive View Controller, но это только происходит и становится серьезной проблемой в приложениях с достаточной сложностью.

Есть несколько методов, которые разработчик может использовать, чтобы сделать View Controller более управляемым. Некоторые примеры:

  • Извлечение логики VC для других классов, таких как источник данных методов табличного представления, и делегирование для других файлов с использованием шаблона проектирования делегата.
  • Создайте более четкое разделение обязанностей с композицией (например, разделите ВК на контроллеры дочерних представлений).
  • Используйте шаблон проектирования координатора, чтобы снять ответственность за реализацию логики навигации в ВК
  • Используйте класс-оболочку DataPresenter, который инкапсулирует логику и преобразует модель данных в выходные данные, представляющие данные, представленные конечному пользователю.

MVC против MVP

Как вы видите диаграмму MVP очень похож на MVC

MVC был шагом вперед, но он все еще был отмечен отсутствием или молчанием о некоторых вещах.

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

В MVC я думаю, что ничто не указывает на то, что Контроллер не должен знать конкретную реализацию View (отсутствие).

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

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

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

В MVP и MVVM уровень просмотра должен быть глупым без всякой логики или интеллекта, а в iOS контроллер представления должен быть частью уровня просмотра. Тот факт, что View является немым, означает, что даже логика представления остается вне уровня View.

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

Если роль модели состоит в том, чтобы просто предоставлять «необработанные» данные, это означает, что код в представлении будет:

Рассмотрим следующий пример: у нас есть пользователь с именем и фамилией. В представлении нам нужно отобразить имя пользователя как «Фамилия, Имя» (например, «Flores, Tiago»).

Если роль модели заключается в предоставлении «сырых» данных, это означает, что код в представлении будет:

let firstName = userModel.getFirstName ()
let lastName = userModel.getLastName ()
nameLabel.text = lastName + «,« + firstName

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

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

let name = userModel.getDisplayName ()
nameLabel.text = name

MVP ясно об этом, и логика представления остается на уровне презентатора. Это увеличивает тестируемость уровня Presenter. Теперь слой Model и Presenter легко тестируется.

Обычно в реализациях MVP представление скрыто за интерфейсом / протоколом, и в Presenter не должно быть ссылок на UIKit.

Еще одна вещь, которую нужно иметь в виду, это переходные зависимости.

Если у Контроллера есть бизнес-уровень в качестве зависимости, а у бизнес-уровня есть уровень доступа к данным в качестве зависимости, то у контроллера есть транзитивная зависимость для уровня доступа к данным. Поскольку реализации MVP обычно используют контракт (протокол) между всеми уровнями, у него нет транзитивных зависимостей.

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

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

Таким образом, контракты (протоколы) создают разделение между уровнями.

MVP против MVVM

Диаграмма MVVM

Одно из основных различий между MVP и MVVM заключается в том, что в MVP Presenter связывается с View через интерфейсы, а в MVVM View ориентируется на изменения данных и событий.

В MVP мы делаем ручную привязку между Presenter и View, используя интерфейсы / протоколы.
В MVVM мы делаем автоматическое связывание данных, используя что-то вроде RxSwift, KVO или используем механизм с обобщениями и замыканиями.

В MVVM нам даже не нужен контракт (например, интерфейс Java / протокол iOS) между ViewModel и View, потому что мы обычно общаемся через Шаблон проектирования Observer.

MVP использует шаблон делегирования, потому что слой презентатора делегирует заказы на уровень представления, поэтому ему необходимо что-то знать о представлении, даже если это только сигнатура интерфейса / протокола. Подумайте о разнице между Центром уведомлений и делегатами TableView. Центру уведомлений не нужны интерфейсы для создания канала связи, но TableView Delegates использует протокол, который должны реализовать классы.

Подумайте о логике представления индикатора загрузки. В MVP ведущий делает ViewProtocol.showLoadingIndicator. В MVVM может быть свойство isLoading во ViewModel. Слой View с помощью автоматической привязки данных обнаруживает изменение этого свойства и обновляет себя. MVP является более важным, чем MVVM, потому что докладчик дает заказы.

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

MVVM проще тестировать, чем MVP, потому что MVVM использует шаблон проектирования Observer, который переносит данные между компонентами в несвязном виде.
Таким образом, мы можем протестировать, просто взглянув на изменения в данных, просто сравнив два объекта, а не создавая ложные вызовы методов для проверки связи между View и Presenter.

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

Часть вторая заканчивается здесь. Все отзывы приветствуются. В третьей части будет рассказано о VIPER, VIP, реактивном программировании, компромиссах, ограничениях и контекстуальном смысле.

Спасибо за чтение! Если вам понравилась эта статья, пожалуйста, хлопайте
чтобы другие тоже могли это прочитать :)