Расскажите о паттернах проектирования Singleton, Factory, Decorator и их применении
Что проверяют
Знаете ли вы эти паттерны в Swift-коде и в самом Apple SDK, а не как определения из книги. Больше всего вопросов вызывает Singleton: интервьюер ждёт, что вы сами назовёте его цену. Следом обычно спрашивают, как протестировать класс, который внутри зовёт .shared.
Как отвечать
- Singleton:
static let shared = Service()плюсprivate init(). Инициализацияstatic letв Swift ленивая и потокобезопасная, но изменяемое состояние внутри от этого безопасным не становится: его защищают очередью, локом или делают сам синглтонactor. В Swift 6 со строгой конкурентностью статическое свойство не-Sendableтипа не скомпилируется, поэтому тип придётся сделатьSendable,@MainActorили актором. В SDK таких общих экземпляров много:URLSession.shared,UserDefaults.standard,NotificationCenter.default; - Factory: прячет выбор конкретного типа за одной точкой создания и возвращает протокол, так что вызывающий код не знает о реализации. В iOS это сборка модуля экрана (Assembly или Builder в VIPER), фабрика ячеек по типу модели, статические
make-методы. Стоит различать простую фабрику, фабричный метод, который переопределяют наследники, и абстрактную фабрику для семейства объектов; - Decorator: объект реализует тот же протокол, что и оборачиваемый, и добавляет поведение вокруг вызова. Пример из жизни:
LoggingAPIClientилиCachingAPIClientповерхAPIClient, причём обёртки складываются в цепочку. Близкая идея есть в SwiftUI: каждый модификатор.padding()или.background()оборачивает view в новый тип.
Где спотыкаются
Называют Singleton просто удобным глобальным доступом и не видят минусов: скрытые зависимости и общее состояние, которое протекает между тестами. Сильный ответ: зависимость приходит через протокол в init, а .shared остаётся лишь значением по умолчанию.
Путают потокобезопасную инициализацию static let с потокобезопасностью данных внутри синглтона и уверяют, что гонок там быть не может.
Считают extension декоратором. Extension добавляет методы типу целиком и на этапе компиляции, а декоратор оборачивает конкретный экземпляр в рантайме и может менять поведение уже существующих методов.