← Назад к вопросам

Какие используешь шаблоны проектирования?

2.0 Middle🔥 251 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Применение шаблонов проектирования в 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 образуют мощную архитектуру, которая хорошо масштабируется и поддерживается в крупных приложениях.

Какие используешь шаблоны проектирования? | PrepBro