
Каждый разработчик рано или поздно сталкивается с моментом, когда стандартные решения перестают справляться с возросшими требованиями проекта. Именно в этот момент стоит рассмотреть паттерн "Абстрактная фабрика" — один из мощных инструментов, который помогает строить системы, готовые к расширениям и изменениям. Это не просто шаблон проектирования, это целая философия построения многогранного, но при этом структурированного кода.
Представим ситуацию: приложение должно поддерживать несколько тем оформления, работать с разными базами данных в зависимости от клиентского окружения или отправлять различные уведомления - "Абстрактная фабрика" позволяет элегантно и прозрачно решить эту задачу, позволяя интегрировать новшества без боли и страданий
Что вообще хотим увидеть:

Для начала объявим протоколы которые определяют интерфейсы для объектов оповещения и уведомлений:
protocol Alert {
    func show(in viewController: UIViewController)
}
protocol Notification {
    func send()
}Далее определяем протокол NotificationFactory, который представ��яет собой абстрактную фабрику для создания объектов Alert и Notification:
protocol NotificationFactory {
    func createAlert(title: String, message: String) -> Alert
    func createNotification(title: String, body: String) -> Notification
}Теперь создадим класс BasicNotificationFactory, который реализует протокол NotificationFactory и предоставляет конкретные реализации для создания базовых уведомлений и оповещений. Аналогично создаем класс AdvancedNotificationFactory, но предоставляющий более продвинутые версии уведомлений и оповещений:
class BasicNotificationFactory: NotificationFactory {
    func createAlert(title: String, message: String) -> Alert {
        return BasicAlert(title: title, message: message)
    }
    func createNotification(title: String, body: String) -> Notification {
        return LocalNotification(title: title, body: body)
    }
}
class AdvancedNotificationFactory: NotificationFactory {
    func createAlert(title: String, message: String) -> Alert {
        return AdvancedAlert(title: title, message: message)
    }
    func createNotification(title: String, body: String) -> Notification {
        return PushNotification(title: title, body: body)
    }
}Теперь объявим протокол FactoryCreator, который определяет интерфейс для создания объектов типа NotificationFactory. Это "фабрика фабрик".
protocol FactoryCreator {
    func createFactory() -> NotificationFactory
}Далее создаем класс BasicFactoryCreator, реализующий протокол FactoryCreator, предоставляет метод для создания экземпляра BasicNotificationFactory и класс AdvancedFactoryCreator, аналогичный BasicFactoryCreator, но создаёт экземпляр AdvancedNotificationFactory:
class BasicFactoryCreator: FactoryCreator {
    func createFactory() -> NotificationFactory {
        return BasicNotificationFactory()
    }
}
class AdvancedFactoryCreator: FactoryCreator {
    func createFactory() -> NotificationFactory {
        return AdvancedNotificationFactory()
    }
}Мы определили семейство связанных или зависимых объектов без указания конкретных классов. FactoryCreator позволяет переключаться между разными "семействами" объектов (базовыми и продвинутыми версиями уведомлений и оповещений), а NotificationFactory отвечает за создание этих объектов.
Переходим к созданию сервиса NotificationService. Этот класс будет управлять всеми операциями, связанными с уведомлениями в приложении, а также представляет собой сервисный слой, который абстрагирует логику создания и управления уведомлениями, делая ее более модульной и удобной для повторного использования в разных частях приложения:
class NotificationService {
    
    var factory: NotificationFactory = BasicNotificationFactory()
    func requestNotificationPermission(completion: @escaping (Bool) -> Void) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
            if let error = error {
                print("Error requesting permission to send notifications: \(error)")
            }
            completion(granted)
        }
    }
    func createAndShowAlert(in viewController: UIViewController, title: String, message: String) {
        let alert = factory.createAlert(title: title, message: message)
        alert.show(in: viewController)
    }
    func sendNotification(title: String, body: String) {
        let notification = factory.createNotification(title: title, body: body)
        notification.send()
    }
    func switchFactory(to newFactory: NotificationFactory) {
        factory = newFactory
    }
}объявляем свойство factory, которое является типом NotificationFactory. По умолчанию оно инициализируется как BasicNotificationFactory. Это означает, что изначально используются базовые реализации уведомлений и оповещений.
объявляем метод для запроса разрешения на отправку уведомлений requestNotificationPermission()
внутри метода requestNotificationPermission, используем UNUserNotificationCenter для запроса разрешения на показ уведомлений с опциями .alert и .sound. В замыкании обрабатываем результат запроса
createAndShowAlert(): метод для создания и отображения оповещения, использует factory для создания оповещения (Alert) и затем отображает его в переданном контроллере
sendNotification(): метод для отправки уведомления. Аналогично предыдущему методу использует factory для создания объекта Notification и затем отправляет уведомление
switchFactory(): метод для изменения фабрики уведомлений. Это позволяет переключаться между различными реализациями фабрик (например, между базовой и продвинутой), изменяя способ создания уведомлений и оповещений
Наконец переходим в контроллер:
import UIKit
class ViewController: UIViewController {
    
    private let notificationService = NotificationService()
    lazy var alertButton: UIButton = {
        let button = UIButton()
        button.setTitle("Show Notification", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.addTarget(self, action: #selector(showAlertButtonTapped), for: .touchUpInside)
        return button
    }()
    lazy var toggleFactoryButton: UIButton = {
        let button = UIButton()
        button.setTitle("Switch to Advanced Factory", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.addTarget(self, action: #selector(toggleFactory), for: .touchUpInside)
        return button
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        setupConstraints()
        notificationService.requestNotificationPermission { granted in
            if granted {
                print("Уведомления разрешены.")
                // Здесь можно запланировать какие-то уведомления или выполнить другие действия, требующие разрешения на уведомления.
            } else {
                print("Уведомления не разрешены.")
                // Здесь можно обработать ситуацию, когда пользователь отказал в разрешении.
            }
        }
        UNUserNotificationCenter.current().delegate = self
    }
    private func setupViews() {
        view.backgroundColor = .white
        view.addSubview(alertButton)
        view.addSubview(toggleFactoryButton)
    }
    private func setupConstraints() {
        alertButton.translatesAutoresizingMaskIntoConstraints = false
        alertButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        alertButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        toggleFactoryButton.translatesAutoresizingMaskIntoConstraints = false
        toggleFactoryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        toggleFactoryButton.topAnchor.constraint(equalTo: alertButton.bottomAnchor, constant: 20).isActive = true
    }
    @objc func showAlertButtonTapped() {
        notificationService.createAndShowAlert(in: self, title: "Attention", message: "This is an example of an abstract factory.")
        notificationService.sendNotification(title: "Hello", body: "This is a local notification.")
    }
    @objc func toggleFactory() {
        if let _ = notificationService.factory as? BasicNotificationFactory {
            notificationService.switchFactory(to: AdvancedNotificationFactory())
            toggleFactoryButton.setTitle("Switch to Basic Factory", for: .normal)
        } else {
            notificationService.switchFactory(to: BasicNotificationFactory())
            toggleFactoryButton.setTitle("Switch to Advanced Factory", for: .normal)
        }
    }
}
extension ViewController: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        completionHandler([.banner, .list, .sound])
    }
}private let notificationService = NotificationService(): создаем экземпляр нашего сервиса, который будет использоваться для управления уведомлениями
накидываем UI и раскидываем якоря
showAlertButtonTapped(): создает и показывает оповещение, а также отправляет уведомление
toggleFactory(): переключает между базовой и продвинутой фабриками уведомлений и изменяет текст кнопки
extension ViewController: UNUserNotificationCenterDelegate: определяет поведение при получении уведомлений, когда приложение активно
В этом контроллере основной фокус идет на взаимодействие пользователя с интерфейсом для демонстрации различных типов уведомлений, создаваемых через абстрактную фабрику, и управления разрешениями на уведомления.
На этом на сегодня все, как сказал один класс к другому: "Я думал, мы можем быть друзьями, но ты постоянно создаешь что-то новое."