Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Models tree

Models tree

An architecture based on recursion

Avatar for mmrmmlrr

mmrmmlrr

March 28, 2016

Other Decks in Programming

Transcript

  1. Здесь мы задумываемся об архитектуре будущей постройки. Пусть в доме

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

    A. Shared object
 В этом случае и второй дом подключится
 к электростанции напрямую. B. Dependency injection
 Первый дом поделится своими зависимостями, чтобы «запитать» второй.

  3. Дальнейший рост структуры приложения происходит по той же схеме: зависимости

    передаются от ближайшего, или порождающего объекта.
  4. «Район», некоторый сценарий работы, завершен. Мы не встретили больших проблем,

    кроме рутины по передаче зависимостей
 на каждом шаге. Архитектура работает. Но вот мы получаем задание: через дорогу начинается стройка больницы. И ей необходимо электричество. (Модальная презентация).
  5. • Электростанцию строить нельзя, она уже есть. • Мы не

    будем строить новую магистраль
 от электростанции, так как отпадет смысл
 в предыдущих ухищрениях. • Петрович из четвертого дома удачно живет прямо у дороги, он и поделится электричеством, а также всеми остальными коммуникациями.
  6. Дома — ячейки архитектуры, MVC-, MVVM-, либо VIPER-модули.
 
 Возможно,

    каждый дом в отдельности идеально реализует принципы SOLID. В приложении, однако, есть проблемы, которые сами по себе архитектурные подходы не решают.
  7. Models Tree Подход, основанный на MVC с активной моделью, при

    котором проект строится иерархически
  8. • Модель создается с родителем. • Модель имеет сет дочерних

    моделей. • Дочерние модели удерживаются в памяти только благодаря родителю.
  9. Проблемы: • Кто будет держать в памяти модель Main Screen?

    • Main Screen по-прежнему ожидает божественной инъекции.
  10. Валидное состояние: В валидном состоянии логика находится, если
 в полной

    мере реализует задачу из предметной области. Задача «система распознала пользователя, развернула периферию и готова к работе» тоже относится к бизнес-логике, это важная «фича» на раннем этапе разработки. Раз есть бизнес-логика, должна быть и соответсвующая модель. Таким образом, при помощи моделей реализован весь пользовательский опыт, включая авторизацию.
  11. Проблемы: • Кто будет держать в памяти модель Main Screen?

    • Main Screen по-прежнему ожидает божественной инъекции. Решение:
  12. Что изменилось: • Session теперь не суперобъект, а корневая часть

    логики. • Main Screen стал рядовым объектом. • Session удерживается в памяти контроллером сессий, но явно с ним не взаимодействует.
 Завершение сессии автоматически выгрузит из памяти все сервисы и модели.
  13. Рекурсивная инъекция зависимостей: c • Сервисы доступны любой модели дерева.

    • Честный DI: дерево пользуется своими,
 а не глобальными ресурсами. • Вложенность не добавляет код.
  14. Плохо: • Победили вязкозть, но запутали логику. • Вынужденно пользуемся

    синглтоном. • Используем чужеродный объект. • Многократное повторение ведет
 к трудноисправимым ошибкам.
  15. Преимущества: • Внутренний механизм. • Готовая структура. • Доставка независимо

    от пути. • Минимум кода. • Усложнение системы не усложняет механизм.
  16. Cхема похожа на работу с уведомлениями,
 однако есть отличия: Перехват

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

    ошибку родителю: При получении ожидаемой ошибки в модели срабатывает сигнал: Так модель регистрируется на ошибку:
  18. Механизм аналогичен распространению ошибок (только вверх). Удобно для перехвата откликов,

    не требующих распространения на все дерево. Например, команда «открыть боковое меню» может быть отправлена из любой модели Main Flow, модель сценария перехватит и выполнит ее.
  19. Модель не обязательно представляет экран. Скорее, это частный случай. Иногда

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

    встроенные в дерево, легко переиспользовать. Инкапсуляция: каждый строительный блок
 в дереве моделей отвечает за определенную задачу, но все они работают вместе. Моделей столько, сколько этого требует логика, без привязки к экранам.
  21. Бизнес-логика может выполняться и сама по себе, без представления, мы

    лишь не увидим результатов и не сможем давать новые команды. Логика не знает о UIKit. «Ядро» будет работать
 и под OS X. Представление, пусть это будет UIViewController, держит слабую ссылку на модель, ведь как мы помним, модель удерживается в памяти родителем.
  22. Активная модель: Представление способно лишь реагировать
 на обновления в модели

    и передавать ей пользовательские команды. Модель ничего не знает ни о представлении,
 ни о реализации родителя. Сигналы — идеальная метафора для этого подхода.
  23. class Houston: SputnikDelegate, ExplorerDelegate, AvangardDelegate, LunaDelegate, VoyagerDelegate, MarsOneDelegate, RangerDelegate, MarinerDelegate,

    SpaceSixtyDelegate, SurveyorDelegate, LunarOrbiterDelegate, VenusFiveDelegate, ISSDelegate, ApolloDelegate, SkylabDelegate, HeliosDelegate, VegaDelegate, HubbleDelegate,
 DeepSpaceOneDelegate, … if self.houston != nil && if self.houston is ISSDelegate { ISSDelegate, self.houston.ISS(self, hasGotAProblem: problem)
  24. МКС вынужден держать ЦУП
 «Хьюстон» как свойство. МКС нагружен ненужным

    знанием. Хьюстон декларирует
 каждый новый «навык». Единственный подписчик.
  25. Модели Exam Creation Flow экран не достался. Она контролирует свое

    «поддерево», управляет данными, но непосредственно на экране не представлена. Кто-то в слое представления должен «строить» иерархию контроллеров вида в соответствии
 с ее активностью. UINavigationController — дословно: контроллер навигации пользовательского интерфейса.
  26. Отображением создания экзамена управляет подкласс контроллера навигации. Он является представлением

    для родительской модели. При необходимости может держать ссылки
 на определенные контроллеры в своем стеке
 для передачи откликов. (хотя это и плохой подход) Логика создания экзамена по-прежнему принадлежит слою модели, контроллер навигации лишь преобразует структуру поддерева в «экраны».
  27. 1. Модель, связанная с контроллером навигации, получает команду «запушить» дочернюю

    модель. 2. Модель создается с правильным родителем. 3. Срабатывает pushChildSignal, подписанный 
 на него UINavigationController создает подходящий вид и связывает его с моделью. 4. UINavigationController выполняет push стека навигации.
  28. Модель не знает о представлении. Однако при связывании с видом

    она может подписаться на его deinitSignal. Этот сигнал — свойство UIViewController, срабатывает перед его деаллокацией.
  29. Итоги: Подход ModelTree решает проблемы распространения ошибок и уведомлений. Сложность

    проекта и кода — постоянная величина. Неявная инъекция зависимостей. Масштабируемость — одно из базовых свойств. Базовые классы неизменны. Платформонезависимость логики.