Какие используешь шаблоны проектирования?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Применение шаблонов проектирования в iOS-разработке
В iOS-разработке я сознательно применяю различные шаблоны проектирования, выбирая их в зависимости от контекста задачи, масштабируемости приложения и требований к поддержке кода. Вот основные категории и конкретные примеры:
Архитектурные шаблоны
MVC (Model-View-Controller) — базовый шаблон Apple, но в чистом виде на iOS он часто превращается в Massive View Controller. Поэтому я его модифицирую:
// Пример разделения ответственности в MVC
class UserModel {
var name: String
var email: String
}
protocol UserViewDelegate: AnyObject {
func didUpdateUser(_ user: UserModel)
}
class UserViewController: UIViewController {
private var userModel: UserModel
private let networkService: NetworkServiceProtocol
// Делегирование части логики сервисам
}
MVVM (Model-View-ViewModel) — мой основной выбор для сложных экранов благодаря реактивному программированию и тестируемости:
class LoginViewModel {
@Published var email: String = ""
@Published var password: String = ""
@Published var isValid: Bool = false
private func validateInputs() {
isValid = !email.isEmpty && password.count >= 6
}
}
// Во ViewController остается только биндинг данных
Coordinator — обязательный шаблон для навигации, который полностью отделяет логику переходов от ViewController:
protocol Coordinator {
var childCoordinators: [Coordinator] { get set }
var navigationController: UINavigationController { get set }
func start()
}
class MainCoordinator: Coordinator {
func showDetail(for product: Product) {
let detailCoordinator = DetailCoordinator(
navigationController: navigationController,
product: product
)
detailCoordinator.start()
childCoordinators.append(detailCoordinator)
}
}
Порождающие шаблоны
Singleton — использую осторожно, только для действительно единственных экземпляров (Logger, AnalyticsService):
class AnalyticsService {
static let shared = AnalyticsService()
private init() {}
private func track(event: String) {
// Отправка события
}
}
Factory Method и Abstract Factory — для создания сложных объектов и семейств связанных объектов:
protocol UIThemeFactory {
func createButton() -> UIButton
func createLabel() -> UILabel
}
class DarkThemeFactory: UIThemeFactory {
func createButton() -> UIButton {
let button = UIButton()
button.backgroundColor = .darkGray
return button
}
}
Builder — для пошагового создания сложных объектов (например, конфигурации сетевых запросов):
class NetworkRequestBuilder {
private var url: URL?
private var method: HTTPMethod = .get
private var headers: [String: String] = [:]
func setURL(_ url: URL) -> Self {
self.url = url
return self
}
func build() -> URLRequest? {
guard let url = url else { return nil }
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
headers.forEach { request.setValue($1, forHTTPHeaderField: $0) }
return request
}
}
Структурные шаблоны
Decorator — через расширения протоколов (Protocol Extensions) в Swift:
protocol DataService {
func fetchData() -> Data
}
class LoggingDecorator: DataService {
private let wrapped: DataService
init(_ service: DataService) {
self.wrapped = service
}
func fetchData() -> Data {
print("Начало загрузки данных")
let data = wrapped.fetchData()
print("Данные загружены, размер: \(data.count) байт")
return data
}
}
Adapter — для адаптации сторонних библиотек или устаревшего кода:
protocol NewPaymentSystem {
func processPayment(amount: Decimal) -> Bool
}
class LegacyPaymentAdapter: NewPaymentSystem {
private let legacySystem: LegacyPaymentProcessor
func processPayment(amount: Decimal) -> Bool {
// Конвертация в старый формат
return legacySystem.process(amount: amount.doubleValue)
}
}
Поведенческие шаблоны
Observer — через Combine или собственные реализации для реактивного программирования:
class UserSettings {
static let shared = UserSettings()
var currentTheme = CurrentValueSubject<Theme, Never>(.light)
}
// Подписчик автоматически обновляет интерфейс
settings.currentTheme
.sink { theme in
applyTheme(theme)
}
.store(in: &cancellables)
Delegate — фундаментальный шаблон iOS, который я использую для обратных вызовов между компонентами:
protocol ImageDownloaderDelegate: AnyObject {
func didDownloadImage(_ image: UIImage)
func didFailWithError(_ error: Error)
}
class ImageDownloader {
weak var delegate: ImageDownloaderDelegate?
private func handleCompletion(_ result: Result<UIImage, Error>) {
switch result {
case .success(let image):
delegate?.didDownloadImage(image)
case .failure(let error):
delegate?.didFailWithError(error)
}
}
}
Strategy — для инкапсуляции алгоритмов и возможности их замены в рантайме:
protocol SortingStrategy {
func sort<T: Comparable>(_ array: [T]) -> [T]
}
class QuickSortStrategy: SortingStrategy {
func sort<T: Comparable>(_ array: [T]) -> [T] {
// Реализация быстрой сортировки
return array.sorted()
}
}
class DataProcessor {
private var sortingStrategy: SortingStrategy
func processData(_ data: [Int]) -> [Int] {
return sortingStrategy.sort(data)
}
}
Критерии выбора шаблонов
При выборе шаблона я руководствуюсь несколькими принципами:
- Соответствие задаче: Не использую шаблоны "просто потому что", а выбираю наиболее подходящий для конкретной проблемы
- Сложность кода: Простые задачи решаю простыми средствами, без излишнего усложнения
- Тестируемость: Предпочитаю шаблоны, которые позволяют легко писать unit-тесты (как MVVM)
- Сопровождение: Учитываю, кто будет поддерживать код и насколько шаблон распространен в команде
- Производительность: Некоторые шаблоны (как чрезмерное использование делегатов) могут влиять на производительность
Важное замечание: Я избегаю фанатичного следования шаблонам. Иногда лучшее решение — это простой, понятный код без строгого следования какому-либо шаблону, особенно в небольших проектах или изолированных модулях. Главное — соблюдение принципов SOLID и DRY, которые часто более важны, чем конкретная реализация шаблона.
На практике я часто комбинирую шаблоны: например, MVVM + Coordinator + Repository образуют мощную архитектуру, которая хорошо масштабируется и поддерживается в крупных приложениях.