Паттерны проектирования кратко swift

Обновлено: 07.07.2024

Абстрактная фабрика

Позволяет создавать семейства связанных объектов, не привязываясь к конкретным классам создаваемых объектов.

Строитель

Строитель

Позволяет создавать сложные объекты пошагово. Строитель даёт возможность использовать один и тот же код строительства для получения разных представлений объектов.

Фабричный метод

Фабричный метод

Определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов.

Прототип

Прототип

Позволяет копировать объекты, не вдаваясь в подробности их реализации.

Одиночка

Одиночка

Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.

Структурные паттерны

Адаптер

Адаптер

Позволяет объектам с несовместимыми интерфейсами работать вместе.

Мост

Разделяет один или несколько классов на две отдельные иерархии — абстракцию и реализацию, позволяя изменять их независимо друг от друга.

Компоновщик

Компоновщик

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

Декоратор

Декоратор

Фасад

Фасад

Предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку.

Легковес

Легковес

Позволяет вместить бóльшее количество объектов в отведённую оперативную память. Легковес экономит память, разделяя общее состояние объектов между собой, вместо хранения одинаковых данных в каждом объекте.

Заместитель

Заместитель

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

Поведенческие паттерны

Цепочка обязанностей

Цепочка обязанностей

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

Команда

Команда

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

Итератор

Итератор

Даёт возможность последовательно обходить элементы составных объектов, не раскрывая их внутреннего представления.

Посредник

Посредник

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

Снимок

Снимок

Позволяет делать снимки состояния объектов, не раскрывая подробностей их реализации. Затем снимки можно использовать, чтобы восстановить прошлое состояние объектов.

Наблюдатель

Наблюдатель

Создаёт механизм подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах.

Состояние

Состояние

Позволяет объектам менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта.

Стратегия

Стратегия

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

Шаблонный метод

Шаблонный метод

Определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Паттерн позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры.

Посетитель

Посетитель

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


Делаете все по MVC, а получается некрасиво? Сомневаетесь, переходить ли на MVVM? Слышали о VIPER, но не уверены, стоит ли оно того?

В этой статье я кратко рассмотрю некоторые популярные архитектурные паттерны в среде iOS и сравню их в теории и на практике. Больше информации вы найдете при переходе по ссылкам, указанным в тексте.

Освоение паттернов может вызвать зависимость, так что будьте осторожны: в
конечном итоге вы, возможно, станете задавать себе больше вопросов, чем до прочтения этой статьи, например:
— Кто должен владеть сетевыми запросами: Model или Controller?
— Как я могу передать Model во ViewModel нового View?
— Кто создает новый модуль VIPER: Router или Presenter?


Почему стоит позаботиться о выборе архитектуры?

  • этот класс — наследник UIViewController;
  • данные сохраняются прямо в UIViewController;
  • UIView-подклассы ни за что не отвечают;
  • Model — это просто контейнер для данных;
  • вы не делаете юнит-тесты.
  • сбалансированное распределение обязанностей между сущностями с жесткими ролями;
  • тестируемость. Обычно вытекает из первого признака (без паники, это легкоосуществимо при соответствующей архитектуре);
  • простота использования и низкая стоимость обслуживания.

Почему распределение?

Распределение уменьшает нагрузку на мозг, когда мы пытаемся выяснить, как работает та или иная сущность. Если вы думаете, что чем больше развиваетесь, то тем лучше мозг будет адаптироваться к пониманию сложных концепций — вы правы. Но у всего есть предел, и он достигается довольно быстро. Таким образом, самый простой способ уменьшить сложность заключается в разделении обязанностей между несколькими сущностями по принципу единой ответственности.

Почему тестируемость?

Почему простота использования?

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

Основы MV(X)

  • Models — ответственные за данные домена или слой доступа к данным, который манипулирует данными, например, класс Person или PersonDataProvider;
  • Views — ответственные за уровень представления (GUI); для окружающей среды iOS это все, что начинается с префикса UI;
  • Controller / Presenter / ViewModel — посредник между Model и View; в целом отвечает за изменения Model, реагируя на действия пользователя, выполненные на View, и обновляет View, используя изменения из Model.
  • лучше понимать их;
  • повторно их использовать (в основном применимо к View и Model);
  • тестировать их отдельно друг от друга.

Как было раньше


Традиционный MVC кажется неприменимым к современной iOS разработке.

MVC от Apple

Ожидания


Controller является посредником между View и Model, следовательно, две последних не знают о существовании друг друга. Поэтому Controller трудно повторно использовать, но это, в принципе, нас устраивает, так как мы должны иметь место для той хитрой бизнес-логики, которая не вписывается в Model.

В теории все выглядит очень просто, но вы чувствуете, что что-то не так, верно? Вы наверняка слышали, что люди расшифровывают MVC как Massive View Controller. Кроме того, разгрузка ViewController стала важной темой для iOS-разработчиков. Почему это происходит, если в Apple просто взяли традиционный MVC и немного его улучшили?

Реальность


Сколько раз вы видели такой код:

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

Cocoa MVC обосновано расшифровывают как Massive View Controller.

Проблема не очевидна, пока дело не доходит до юнит-тестов (надеюсь, что в вашем проекте оно все же доходит). Так как View Controller тесно связана с View, ее становится трудно тестировать, и приходится идти изощренным путем, заменяя View Mock-объектами и имитируя их жизненный цикл, а также писать код View Controller таким образом, чтобы бизнес-логика была по максимуму отделена от кода view layout.

Кажется, это сложно протестировать, не так ли? Мы можем выделить генерацию приветствия в новый класс GreetingModel и тестировать ее отдельно, но мы не можем протестировать логику представления (хоть в примере ее не так много) внутри GreetingViewController без вызова методов жизненного цикла View напрямую (viewDidLoad, didTapButton), что может привести к загрузке всех UIView, и это плохо для юнит-тестов.

На самом деле, тестирование UIViews на одном симуляторе (например, iPhone 4S) не гарантирует, что он будет работать нормально на других устройствах (например, iPad), так что я рекомендую убрать галочку Host Application из конфигурации таргета юнит-тестов и запускать их на симуляторе, не включая само приложение.

Взаимодействие между View и Controller на самом деле не особо поддается тестированию с помощью юнит-тестов.

  • распределение: View и Model на самом деле разделены, но View и Controller тесно связаны;
  • тестируемость: из-за плохого распределения вы, вероятно, будете тестировать только Model;
  • простота использования: наименьшее количество кода среди других паттернов. К тому же он выглядит понятным, поэтому его легко может поддерживать даже неопытный разработчик.

Cocoa MVC является лучшим архитектурным паттерном с точки зрения скорости разработки.

Реализация обещаний Cocoa MVC



С точки зрения MVP, подклассы UIViewController на самом деле есть View, а не Presenter. Это различие обеспечивает превосходную тестируемость, которая идет за счет скорости разработки, потому что вы должны связывать вручную данные и события именно между View и Presenter, как можно увидеть на примере ниже.

Важное примечание относительно сборки

MVP является первым паттерном, выявляющим проблему сборки, которая происходит из-за наличия трех действительно отдельных слоев. Так как нам не нужно, чтобы View знала о Model, выполнять сборку в презентующей View Controller (который на самом деле View) неправильно, следовательно, это нужно сделать в другом месте. Например, можно создать сервис Router, который будет отвечать за выполнение сборки и презентацию View-to-View. Эта проблема возникает не только в MVP, ее также нужно решать во всех последующих паттернах.

  • распределение: большая часть ответственности разделена между Presenter и Model, а View ничего не делает;
  • тестируемость: отличная, мы можем проверить большую часть бизнес-логики благодаря бездействию View;
  • простота использования: в нашем нереально простом примере количество кода в два раза больше по сравнению с MVC, но в то же время идея MVP очень проста.


Существует другой вариант MVP — MVP с надзирающим контроллером. Он включает в себя прямое связывание View и Model, в то время как Presenter (надзирающий контроллер) по-прежнему обрабатывает действия с View и способен изменять ее.


Но, как мы уже узнали ранее, расплывчатое разделение ответственности плохо само по себе, равно как и тесная связанность между View и Model. А я не вижу смысла в написании примера для плохой архитектуры.

Самая новая из MV(X) вида.

MVVM является новейшим из MV(X) паттернов, так что будем надеяться, что он появился с учетом всех проблем, присущих MV(X).

В теории Model-View-ViewModel выглядит очень хорошо. View и Model уже нам знакомы, как и View Model в качестве посредника.


  • MVVM рассматривает View Controller как View;
  • в нем нет тесной связи между View и Model.

Так что такое View Model в среде iOS? Єто независимое от UIKit представление View и ее состояния. View Model вызывает изменения в Model и самостоятельно обновляется с уже обновленной Model. И так как биндинг происходит между View и View Model, то первая, соответственно, тоже обновляется.

Биндинги

  • одну из биндинг-библиотек, основанных на KVO (например,RZDataBinding или SwiftBond);
  • полноразмерный фреймворк для функционального реактивного программирования, такой как ReactiveCocoa, RxSwift или PromiseKit.

Есть одна горькая правда об FRP-фреймворках: великая сила приходит с большой ответственностью. Очень легко все поломать, когда вы пишете реактивно. Другими словами, если что-то пошло не так, вы можете потратить много времени на отладку приложения. Стоит просто взглянуть на этот стек вызовов.


VIPER

Опыт строительства из кубиков Lego, перенесённый на проектирование iOS-приложений

VIPER — наш последний кандидат, который особенно интересен, потому что он не из категории MV(X).

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


  • Interactor содержит бизнес-логику, связанную с данными (Entities): например, создание новых экземпляров сущностей или получение их с сервера. Для этих целей вы будете использовать некоторые Сервисы и Менеджеры, которые рассматриваются скорее как внешние зависимости, а не как часть модуля VIPER.
  • Presenter содержит бизнес-логику, связанную c UI (но UIKit-независимую), вызывает методы в Interactor.
  • Entities — простые объекты данных, не являются слоем доступа к данным, потому что это ответственность слоя Interactor.
  • Router несет ответственность за переходы между VIPER-модулями.
  • логика из Model (взаимодействие данных) смещается в Interactor, а также есть Entities — структуры данных, которые ничего не делают;
  • из Controller, Presenter, ViewModel обязанности представления UI переехали в Presenter, но без возможности изменения данных;
  • VIPER является первым шаблоном, который пробует решить проблему навигации, для этого есть Router.

В примере нет маршрутизации или взаимодействия между модулями, так как эти темы совсем не охвачены MV(X)-паттернами.

  • Распределение. Несомненно, VIPER является чемпионом в распределении обязанностей.
  • Тестируемость. Здесь нет ничего удивительного: лучше распределение — лучше тестируемось.
  • Простота использования. Как вы уже догадались, первые два преимущества идут за счет стоимости сопровождения. Вам придется писать огромное количество интерфейсов для классов с незначительными обязанностями.

Так что там c Lego?

При использовании VIPER вам может показаться, что вы строите Эмпайр Стейт Билдинг из кубиков Lego, и это говорит о том, что у вас есть проблемы. Может быть, вы слишком рано взялись за VIPER и стоит рассмотреть что-то попроще. Некоторые люди игнорируют это и продолжают стрелять из пушки по воробьям. Я предполагаю, что они верят, что их приложения получат выгоду из VIPER когда-нибудь в будущем, даже если сейчас стоимость обслуживания неоправданно высока. Если вы считаете, что оно того стоит, то я рекомендую вам попробовать Generamba — инструмент для генерации скелетонов VIPER. Хотя лично мне кажется, что это сродни использованию автоматического прицела для стрельбы из той же пушки вместо рогатки.

Вывод

Английская версия доступна здесь. Слайды которые я презентовал на NSLondon доступны здесь.


Swift — выпущенный в 2014 году собственный язык программирования Apple — мощный инструмент, который позволяет разработчикам создавать различные приложения для нескольких операционных систем (хотя чаще всего, конечно, для iOS).

Текст предоставлен компанией Ruby Garage.

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

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

Типы шаблонов проектирования ПО

Прежде чем перейти к самым распространенным шаблонам в Swift, расскажем о трех общих типах шаблонов проектирования программного обеспечения и о том, чем они отличаются:

  • Порождающие (Creational) шаблоны дизайна ПО работают с механизмами создания объектов.
  • Структурные (Structural) — направлены на упрощение проекта путем поиска легкого способа реализации взаимосвязей между классами и объектами.
  • Поведенческие (Behavioral) — определяют общие модели взаимодействия между объектами и реализуют эти модели

Общие шаблоны в свою очередь делятся на множество частных шаблонов проектирования, реализующих эти паттерны. Правда большинство из них используются редко, поэтому мы выбрали пять шаблонов проектирования, которые чаще всего используются в Swift для разработки на iOS и других операционных системах.

Часто используемые шаблоны проектирования в Swift

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

“Строитель” — это порождающий шаблон проектирования, который позволяет создавать сложные объекты из простых поэтапно. Этот шаблон помогает использовать один и тот же код для создания различных отражений объектов.

Представьте себе сложный объект, который требует постепенной инициализации нескольких полей и вложенных объектов. Как правило, код инициализации для таких объектов скрыт внутри монстрообразного конструктора с десятками параметров. Или еще хуже — он может быть рассеян по всему коду клиента.

Шаблон “Строитель” требует отделения конструкции объекта от его собственного класса. Зато построение этого объекта поручается специальным объектам, которые называются “строителями”, и разделено на несколько этапов. Для создания объекта вы последовательно вызываете методы “Строителя”, при этом вам не нужно проходить все этапы, а только те, которые необходимы для создания объекта с определенной конфигурацией.

Шаблон проектирования “Строитель” следует применять,

  • если вы хотите избежать использования “телескопического конструктора” (когда конструктор имеет слишком много параметров, становится трудно его читать и управлять им);
  • когда код должен создавать различные представления какого-то определенного объекта;
  • когда нужно собирать сложные объекты.

Пример

Допустим, вы разрабатываете iOS-приложение для ресторана, и вам нужно применить функцию заказа. Вы можете представить две структуры, Dish и Order , а с помощью объекта OrderBuilder можно составлять заказ с различными наборами блюд.

“Адаптер” — структурный шаблон проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Иными словами, он меняет интерфейс объекта, чтобы адаптировать его к другому объекту.

“Адаптер” “заворачивает” объект так, что почти полностью скрывает его от другого объекта. Например, объект, который работает в метрической системе измерения, можно “обернуть” адаптером, который преобразует данные в футы.

Шаблон проектирования “Адаптер” следует применять,

  • когда вы хотите использовать сторонний класс, но его интерфейс не соответствует остальному коду вашей программы;
  • когда вам нужно использовать несколько существующих подклассов, но они не имеют какой-то особой функциональности, и к тому же вы не можете расширить суперкласс.

Пример

Допустим, вы хотите применить функцию календаря и управления событиями в своем iOS-приложении. Для этого следует интегрировать фреймворк EventKit и адаптировать модель Event из фреймворка к модели в вашем приложении. “Адаптер” может “охватить” модель фреймворка и сделать ее совместимой с вашей.

Декоратор — структурный шаблон проектирования, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные “обертки”.

Недаром этот шаблон называют также “Обертка” (Wrapper). Это название более точно описывает его основную идею: вы размещаете целевой объект внутри другого объекта-обертки, который инициирует основное поведение целевого объекта и добавляет свой результат к конечному.

Оба объекта имеют один и тот же интерфейс, поэтому для пользователя не имеет значения, с каким объектом он взаимодействует — “чистым” или “обернутым”. Разработчик же может использовать несколько “оберток” одновременно и получить их комбинированное поведение.

Шаблон проектирования “Декоратор” следует применять,

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

Пример

Представьте, что вам нужно внедрить управление данными в своем iOS-приложении. Вы можете создать два “декоратора”: EncryptionDecorator для шифрования и дешифрования данных и EncodingDecorator для кодирования и декодирования.

Фасад — структурный шаблон проектирования, который обеспечивает простой интерфейс для библиотеки, фреймворка или сложной системы классов.

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

Шаблон “Фасад” обеспечивает простой интерфейс для работы со сложными подсистемами, содержащими множество классов. Он предлагает упрощенный интерфейс с ограниченными функциональными возможностями, который можно расширить, используя сложную подсистему направления. Этот упрощенный интерфейс предоставляет только те функции, которые нужны клиенту, скрывая все остальные.

Шаблон проектирования “Фасад” следует применять,

  • когда вы хотите предоставить простой или унифицированный интерфейс сложной подсистеме;
  • когда нужно разложить подсистему на отдельные слои.

Пример

Многие современные мобильные приложения поддерживают запись и воспроизведение звука. Допустим, вам нужно применить эту функцию. Вы можете использовать шаблон “Фасад”, чтобы скрыть реализацию служб, ответственных за файловую систему ( FileService ), аудиосеансы ( AudioSessionService ), аудиозапись ( RecorderService ) и воспроизведение звука ( PlayerService ). “Фасад” обеспечивает упрощенный интерфейс для этой довольно сложной системы классов.

Шаблонный метод — это поведенческий шаблон проектирования, который определяет скелет алгоритма и делегирует ответственность за некоторые шаги подклассам. Этот шаблон позволяет подклассам переопределять отдельные шаги алгоритма, не меняя его общей структуры.

Этот шаблон дизайна разбивает алгоритм на последовательность шагов, описывает эти шаги отдельными методами и вызывает их последовательно с помощью одного шаблона.

Шаблонный метод следует применять,

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

Пример

Допустим, вы работаете над iOS-приложением, которое должно делать и хранить фотографии. Ваша программа должна получить разрешения на использование камеры iPhone и галереи изображений. Для этого вы можете использовать базовый класс PermissionService , который имеет определенный алгоритм. Чтобы получить разрешение на использование камеры и галереи, вы можете создать два подкласса, CameraPermissionService и PhotoPermissionService , которые переопределяют определенные шаги алгоритма, оставляя неизменными другие.

Вывод

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

Возможность выбрать шаблон проектирования в Swift позволяет создавать функциональные и безопасные приложения, которые легко поддерживать и модернизировать. В арсенале любого разработчика должно быть знание и навыки работы с шаблонами проектирования, поскольку они не только упрощают и оптимизируют процесс разработки, но и обеспечивают высокое качество кода.



Программистам нужно знать паттерны. Они очень помогают в работе, облегчают жизнь и просто говорят о том, что вы то уже "не лыком шиты"! Что же такое паттерны? Это отточенные лучшие практики или решения для стандартных задач в объектно-ориентированном программировании. Паттернов достаточно много и более того, зачастую их перемешивают между собой, чтобы получить наиболее рациональные решения для поставленной задачи.

Какую проблему решают паттерны?

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

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

Чему вы научитесь в этом курсе?

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

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

Курс подходит:

  • для начинающих разработчиков, кто уже имеет небольшой опыт работы со Swift
  • для тех, кто уже умеет работать со Swift, но пока не решался познакомиться с паттернами
  • для тех, кто уже программировал на другом объектно-ориентированном языке, но решил перейти в Swift и сразу окунуться в паттерны
  • для обучения работы с протоколами
  • для изучения более глубокого подхода к коду
  • для тех, кто хочет на практике познакомиться с таким понятие как "полиморфизм"
  • кто хочет получить не устаревающие знания, которые можно перенести в любой объектно-ориентированный язык программирования
  • для хардкодеров, которым нравится много кода, очень много кода!

Содержание курса

1. Intro (8:48)
2. Strategy (Стратегия) (14:56)
3. Observer (Наблюдатель) (12:58)
4. Decorator (Декоратор) (16:18)
5. Simple Factory (Простая фабрика) (12:44)
6. Factory Method (Фабричный метод) (10:08)
7. Abstract Factory (Абстрактная фабрика) (10:05)
8. Singleton (Синглтон) (10:30)
9. Command (Команда) (24:34)
10. Adapter (Адаптер) (9:23)
11. Facade (Фасад) (11:13)
12. Template Method (Шаблонный метод) (20:02)
13. Iterator (Итератор) (26:10)
14. Composite (Компоновщик) (12:18)
15. State (Состояние) (18:08)
16. Proxy (Прокси) (15:49)
17. Builder (Строитель) (14:06)
18. Chain of responsibility (Цепочка ответственностей) (12:52)
19. Outro (0:43)

Хотел бы представить на суд читателей новый раздел сайта — Паттерны проектирования в iOS программировании.

Wikipedia нам говорит:

Шаблон проектирования или паттерн (англ. design pattern) в разработке программного обеспечения — повторимая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста.

Prototypeprototype

Прототип – один из самых простых паттернов, который позволяет нам получить точную копию необходимого объекта. Тоесть использовать как прототип для нового объекта.

Когда использовать:
1. У нас есть семейство схожих объектов, разница между которыми только в состоянии их полей.
2. Чтобы создать объект вам надо пройти через огонь, воду и медные трубы. Особенно если этот объект состоит из еще одной кучи объектов, многие из которых для заполнения требуют подгрузку даных из базы, веб сервисов и тому подобных источников. Часто, легче скопировать объект и поменять несколько полей
3. Нам не важно как создается объект.
4. Нам страшно лень писать иерархию фабрик (читай дальше), которые будут инкапсулировать всю противную работу создания объекта

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

Перейдем к примеру

А теперь создадим два объекта нашего класса, поменяем значения свойств, выведем лог и посмотрим что же получится:

Вывод лога в консоль:

Думаю, понятно, что при создании второго указателя secondPerson, он сослался на тот же экземпляр что и firstPerson, и поэтому изменения свойств через один указатель повлияют и на другой.

Именно для создания копии объектов в памяти следует использовать глубокое копирование, которое в Swift реализовано протоколом NSCopying, и методом этого протокола

Изменим реализация нашего класса, чтобы он соответствовал протоколу, и добавим инициализатор от объекта собственно типа.

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

Вполне ожидаемый лог в консоле:

И последнее, что нужно сказать про NSCopyng. Ведь мы нигде не использовали метод этого протокола. Это потому, что NSZone больше не используется в Swift да и в Objective-C в течение длительного времени. И передающийся в этот метод аргумент игнорируется. Этот метод существует по историческим причинам.

Ну и напоследок приведу пример использования шаблона программирования Prototype, реализованного без использования протокола NSCopyng, а лишь преимущества языка программирования Swift. Как было сказано выше — шаблон прототип используется для создания экземпляра нового объекта путем копирования всех свойств существующего объекта, создание независимого клона. Эта практика особенно полезна , когда создание нового объекта является неэффективным.


В следующей стате мы рассмотрим шаблоны программирования Factory:Шаблоны программирования на Swift: Factory

Читайте также: