Какие поведенческие паттерны проектирования ты знаешь?

Ответ

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

Основные паттерны в контексте iOS/macOS разработки:

  1. Делегат (Delegate):

    • Суть: Объект поручает другому объекту (делегату) выполнение части своих задач.
    • Пример: UITableViewDelegate, URLSessionDelegate. Определяет протокол с опциональными методами.
      protocol DataFetcherDelegate: AnyObject {
      func fetcher(_ fetcher: DataFetcher, didReceive data: Data)
      func fetcher(_ fetcher: DataFetcher, didFailWith error: Error)
      }
  2. Наблюдатель (Observer):

    • Суть: Объект (наблюдатель) подписывается на уведомления об изменениях в другом объекте (субъекте).
    • Реализации: NotificationCenter, Key-Value Observing (KVO), реактивные фреймворки (Combine, RxSwift).
      // NotificationCenter
      NotificationCenter.default.addObserver(self,
                                         selector: #selector(handleUpdate),
                                         name: .dataDidUpdate,
                                         object: nil)
  3. Стратегия (Strategy):

    • Суть: Инкапсуляция семейства алгоритмов в отдельные классы, делая их взаимозаменяемыми.
    • Пример: Алгоритмы сортировки, способы оплаты, валидации.
      protocol CompressionStrategy {
      func compress(data: Data) -> Data
      }
      class ZIPStrategy: CompressionStrategy { ... }
      class RARStrategy: CompressionStrategy { ... }
  4. Команда (Command):

    • Суть: Инкапсуляция запроса как объекта, позволяющая параметризовать клиентов с различными запросами, ставить их в очередь или логировать.
    • Пример: UIAlertAction, операции Undo/Redo.
  5. Цепочка обязанностей (Chain of Responsibility):

    • Суть: Передача запроса по цепочке обработчиков. Каждый решает, обработать его или передать дальше.
    • Пример: Цепочка обработчиков сетевого запроса, система событий UIResponder.
  6. Состояние (State):

    • Суть: Объект меняет свое поведение при изменении внутреннего состояния. Каждое состояние представлено отдельным классом.
    • Пример: Управление состоянием плеера (Playing, Paused, Stopped).
  7. Хранитель (Memento):

    • Суть: Сохранение и восстановление состояния объекта без нарушения инкапсуляции.
    • Пример: Архитектура Codable для сериализации, NSCoding.
  8. Посредник (Mediator):

    • Суть: Централизованное взаимодействие между группой объектов, уменьшая их прямые связи.
    • Пример: UINavigationController (посредник между ViewController'ами), координатор сцен (Scene Coordinator).

Ответ 18+ 🔞

Да ты посмотри, какие эти паттерны, блядь, умные придумали! Сидят, сука, где-то в подвале, кофе пьют и думают: "А как бы нам так сделать, чтобы один объект не лез, блядь, ко всем по очереди в сраку, а как-то культурно, по-человечески?" И вот, нате вам — поведенческие паттерны. Это ж как инструкция по выживанию в мире объектов, ёпта!

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

Основные, которые в iOS-разработке прям как родные:

  1. Делегат (Delegate). Ну это классика, блядь, основа основ! Один объект такой: "Ой, я сам это делать не буду, я, блядь, важный. Вот ты, пиздюк, будешь моим делегатом — делай за меня работу, а я тебе звонок дам, когда надо". Как UITableView, который сам рисует ячейки, но спрашивает у тебя: "Слушай, а сколько их там, этих ячеек-то? А что в десятой писать будем?" И ты ему через протокол отвечаешь. Чистая бюрократия, только в коде!

    protocol DataFetcherDelegate: AnyObject {
        func fetcher(_ fetcher: DataFetcher, didReceive data: Data) // Вот, получил данные — на, держи, обрабатывай
        func fetcher(_ fetcher: DataFetcher, didFailWith error: Error) // А тут обосрался — разбирайся сам, я уже ни хуя не могу
    }
  2. Наблюдатель (Observer). Это когда тебе овердохуища интересно, что происходит в другом месте, но лезть туда и спрашивать каждую секунду — западло. Ты такой: "Эй, NotificationCenter, слушай сюда! Как только у этого чувака что-то произойдёт — сразу ори на всю деревню, а я прибегу". И сидишь ждёшь уведомления. Удобно, блядь, но если переборщить с подписками — получается базар, на котором все орут, и нихуя не разберёшь, кто кому что сказал.

    // Сидишь себе, ковыряешь в носу, и вдруг — БАЦ! — уведомление прилетело.
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(handleUpdate),
                                           name: .dataDidUpdate,
                                           object: nil)
  3. Стратегия (Strategy). Вообще гениальная хуйня! Представь: у тебя есть задача, например, сжать файл. Но способов — дохуя: ZIP, RAR, 7z. Вместо того чтобы городить в одной функции if-else на триста строк, ты выносишь каждый алгоритм в отдельный класс, который подписан на один протокол. И потом просто тычешь в основной объект нужную стратегию: "На, сожми вот этим". Хочешь поменять — просто даёшь другую. Гибко, как хуй в бане!

    protocol CompressionStrategy {
        func compress(data: Data) -> Data
    }
    class ZIPStrategy: CompressionStrategy { ... } // Этот жмёт по-здоровому
    class RARStrategy: CompressionStrategy { ... } // А этот — со своими тараканами
  4. Команда (Command). Берёшь какое-то действие, заворачиваешь его в отдельный объект — и вуаля, у тебя теперь есть "пульт". Эту команду можно положить в очередь, отложить на потом, отменить или записать в историю (для Undo). UIAlertAction — это же чистейшая команда! Создал кнопку — создал команду, которая выполнится по тапу.

  5. Цепочка обязанностей (Chain of Responsibility). Это как бюрократическая волокита, но запланированная. Запрос приходит к первому обработчику, тот смотрит: "Моё? Не, не моё". И пихает следующему. Так по цепочке, пока кто-нибудь не возьмёт ответственность на себя или запрос не сгинет в пучине безответственности. Система событий в iOS (UIResponder) — она так и работает: нажали на кнопку — событие пошло гулять по цепочке от вьюхи к контроллеру и выше, пока его не перехватят.

  6. Состояние (State). О, это про нашу изменчивую жизнь! Объект ведёт себя по-разному в зависимости от того, в каком он состоянии. Вместо кучи if (state == .playing) в каждом методе, ты каждое состояние выносишь в отдельный класс. Плеер: один класс для Playing, другой для Paused. Переключил состояние — и объект сам поменял поведение. Красота, блядь!

  7. Хранитель (Memento). Нужен, чтобы сохранять и восстанавливать состояние объекта, не залезая ему в кишки. Как Codable в Swift: объект сам знает, как себя упаковать в данные (encode) и распаковать обратно (decode). Сделал снимок состояния — положил в архив. Захотел откатиться — достал и применил. Магия, ёпта!

  8. Посредник (Mediator). Когда у тебя куча объектов начинают общаться напрямую, получается такая паутина зависимостей, что любое изменение — и всё разваливается, пиздец. Посредник — это такой "главный по тарелочкам". Все общаются только с ним, а он уже решает, кому что передать. UINavigationController — идеальный пример: вьюконтроллеры не знают друг о друге, они просто говорят навигатору "переведи меня туда", а он уже всё организует. Порядок, блядь, а не бардак!

Вот так вот, сука. Эти паттерны — они как правила приличия в мире объектов. Не соблюдаешь — получаешь спагетти-код, в котором через месяц сам нихуя не разберёшься. А с ними — хоть какая-то надежда на то, что всё не развалится при первом же чихе.