Facade: основи патерну фасад у мобільній архітектурі

Автор: IT Sectr Опубліковано: 2026-02-18 Час читання: 9 хв

Facade — це структурний патерн проєктування, який надає спрощений інтерфейс до складної підсистеми класів. У мобільній розробці Facade найчастіше реалізується як Service Layer або UseCase, що приховує взаємодію з мережею, БД та аналітикою. За даними Martin Fowler (Patterns of Enterprise Application Architecture, 2003), Facade — один із ключових патернів для організації сервісного шару.

Головне

  • Facade — структурний патерн, який надає простий інтерфейс до складної системи класів, бібліотек або фреймворків
  • Service Layer — реалізація Facade в мобільній архітектурі, що приховує API, кеш та аналітику від UI
  • Facade не приховує підсистему — клієнт може звертатися до неї напряму за потреби
  • UseCase в Clean Architecture — різновид Facade, що оркеструє один бізнес-сценарій
  • Facade vs Adapter: Facade спрощує інтерфейс, Adapter перетворює один інтерфейс на інший

Що таке патерн Facade?

Facade — структурний патерн, який надає уніфікований інтерфейс до групи інтерфейсів підсистеми. Він визначає високорівневий інтерфейс, що спрощує використання підсистеми. Facade не додає нової функціональності — він оркеструє наявні компоненти, приховуючи складність їхньої взаємодії від клієнта.

Kotlin
// Складна підсистема
class AuthApi {
    suspend fun login(email: String, pass: String): TokenResponse
}

class UserDao {
    suspend fun saveUser(user: UserEntity)
    suspend fun getUser(id: Long): UserEntity?
}

class AnalyticsTracker {
    fun track(event: String, params: Map)
}

// Facade — простий інтерфейс для UI
class AuthService(
    private val api: AuthApi,
    private val dao: UserDao,
    private val analytics: AnalyticsTracker
) {
    suspend fun loginUser(email: String, password: String): Result {
        return runCatching {
            val token = api.login(email, password)
            val user = User(token.userId, email, token.accessToken)
            dao.saveUser(user.toEntity())
            analytics.track("login_success", mapOf("method" to "email"))
            user
        }
    }
}

AuthService — Facade, що приховує AuthApi, UserDao та AnalyticsTracker від ViewModel. UI викликає loginUser(email, password) замість трьох окремих запитів до API, БД та аналітики. Це знижує зв'язність: якщо завтра AuthApi стане FirebaseAuth або UserDao мігрує на Room, зміниться лише Facade, а не UI.

Facade в мобільній архітектурі: Service Layer

Service Layer — поширена реалізація Facade в мобільних застосунках. Він інкапсулює бізнес-логіку та координацію між шарами. В Android Service Layer часто реалізується через UseCase (Clean Architecture), в iOS — через Manager або Service протоколи.

Компонент Роль у підсистемі Що приховує Facade
AuthApi Мережевий запит до сервера Формат запиту, endpoint, обробку помилок HTTP
UserDao Локальне зберігання токена Схему БД, SQL-запити, міграції
AnalyticsTracker Відправлення подій аналітики Firebase/AppMetrica SDK, формат подій
NetworkMonitor Перевірка доступності мережі ConnectivityManager, BroadcastReceiver

AuthService об'єднує всі чотири компоненти. ViewModel викликає один метод, не знаючи, що під капотом відбувається мережевий запит, запис у БД, трекінг та перевірка мережі. При тестуванні AuthService можна замінити mock'ом, перевіривши всю логіку авторизації без інтеграції з реальними компонентами.

Facade vs Adapter vs Mediator

Facade, Adapter і Mediator — структурні патерни, але вирішують різні завдання. Їх часто плутають, оскільки всі три вводять об'єкт-посередник. Розберемо відмінності на прикладі мобільного застосунку.

Аспект Facade Adapter Mediator
Мета Спростити інтерфейс підсистеми Перетворити інтерфейс Зменшити зв'язність компонентів
Напрямок Один інтерфейс → підсистема Клієнт → Adaptee N компонентів ↔ Mediator
Зміна інтерфейсу Створює новий, спрощений Перетворює наявний Не змінює, координує
Чи знає підсистема про патерн? Ні Ні Так, спілкуються через Mediator
Приклад у мобільній розробці UseCase / Service Layer RecyclerView.Adapter Coodinator в iOS

Facade не приховує підсистему — клієнт може за потреби звернутися до AuthApi напряму. Adapter в обов'язковому порядку змінює інтерфейс Adaptee. Mediator координує складні взаємодії між безліччю об'єктів, які можуть не знати одне про одного.

Реалізація Facade на Kotlin для Android

Реалізація Facade на Kotlin для Android з Clean Architecture використовує UseCase як точку входу для кожного бізнес-сценарію. UseCase — це Facade, що приховує репозиторій, мапер та інші залежності від UI-шару.

Kotlin
// Repository — теж Facade, але рівнем нижче
class UserRepositoryImpl(
    private val local: UserLocalDataSource,
    private val remote: UserRemoteDataSource,
    private val mapper: UserMapper
) : UserRepository {
    override suspend fun getUserProfile(id: String): UserProfile {
        val cached = local.getUser(id)
        if (cached != null && !cached.isStale) {
            return mapper.toProfile(cached)
        }
        val dto = remote.fetchUser(id)
        val entity = mapper.toEntity(dto)
        local.saveUser(entity)
        return mapper.toProfile(entity)
    }
}

// UseCase — Facade для бізнес-сценарію
class LoadUserProfileUseCase(
    private val repo: UserRepository,
    private val analytics: AnalyticsTracker
) {
    suspend operator fun invoke(userId: String): Result {
        return runCatching {
            val profile = repo.getUserProfile(userId)
            analytics.track("profile_loaded", mapOf("user_id" to userId))
            profile
        }
    }
}

LoadUserProfileUseCase — Facade для сценарію завантаження профілю. Він приховує логіку кешування (local → remote), маппінг DTO → Entity → Profile та трекінг аналітики. ViewModel викликає invoke(userId) і отримує готовий UserProfile або помилку. UseCase можна тестувати ізольовано, замінюючи репозиторій mock-об'єктом.

Реалізація Facade на Swift для iOS

Facade в iOS часто реалізується як Manager або Service. На відміну від Android, iOS використовує протоколи для визначення інтерфейсу Facade, що дозволяє легко підміняти реалізації в тестах. Розглянемо Facade для роботи з медіа — завантаження, кешування та відображення.

Swift
protocol MediaServiceProtocol {
    func loadImage(from url: URL) async -> Result<UIImage, Error>
}

final class MediaService: MediaServiceProtocol {
    private let cache: ImageCache
    private let downloader: ImageDownloader
    private let decoder: ImageDecoder
    
    func loadImage(from url: URL) async -> Result<UIImage, Error> {
        // 1. Перевірити кеш
        if let cached = cache.image(for: url) {
            return .success(cached)
        }
        // 2. Завантажити дані
        let result = await downloader.download(from: url)
        guard case let .success(data) = result else {
            return .failure(MediaError.downloadFailed)
        }
        // 3. Декодувати
        guard let image = decoder.decode(data) else {
            return .failure(MediaError.decodeFailed)
        }
        // 4. Зберегти в кеш
        cache.setImage(image, for: url)
        return .success(image)
    }
}

MediaService інкапсулює трикроковий процес: кеш → завантаження → декодування. UI викликає один метод loadImage(from:) замість керування ImageCache, URLSession та ImageDecoder. При тестуванні можна підмінити MediaServiceProtocol mock'ом, що повертає попередньо встановлені зображення без реального завантаження.

Типові помилки при використанні Facade

Помилки при проєктуванні Facade зводять нанівець його переваги: замість спрощення виходить God Object, від якого залежить вся система. Розберемо три головні проблеми.

God Facade — занадто багато відповідальності

Коли один Facade містить методи для авторизації, завантаження профілю, відправлення повідомлень та синхронізації — це God Object. Ознака: понад 15 публічних методів в одному класі. Рішення: розділити на кілька спеціалізованих Facade за сферами відповідальності — AuthService, ProfileService, MessagingService.

Facade з витоком деталей підсистеми

Якщо Facade повертає типи, специфічні для підсистеми (наприклад, FirebaseUser або RealmObject), клієнт усе одно прив'язаний до конкретної реалізації. Рішення: Facade має повертати лише власні типи (data class / struct), повністю абстрагуючи клієнта від деталей підсистеми.

Facade як єдина точка входу

Коли Facade забороняє прямий доступ до підсистеми, він стає bottleneck. Іноді клієнту потрібен специфічний метод підсистеми, і змушувати його проходити через Facade — зайво. Facade не має бути суворим gatekeeper: він надає зручний інтерфейс, але не блокує прямий доступ до компонентів.

Часті запитання

У чому різниця між Facade і Proxy?

Facade надає спрощений інтерфейс до підсистеми, часто створюючи новий набір методів. Proxy зберігає той самий інтерфейс, що й оригінальний об'єкт, але додає контроль доступу або ліниве завантаження. Facade — для спрощення, Proxy — для контролю.

Facade — це те саме, що Service Layer?

Service Layer — це реалізація патерну Facade на рівні архітектури застосунку. Він визначає межу між UI та бізнес-логікою, приховуючи деталі реалізації сервісів. В Android Service Layer часто реалізується через UseCase, в iOS — через Manager або Service протоколи.

Коли Facade стає God Object?

God Facade виникає, коли один клас бере на себе відповідальність за кілька незв'язаних підсистем. Ознаки: понад 15 публічних методів, методи з різних доменів (авторизація + платежі + сповіщення), клас, який складно тестувати (понад 10 залежностей). Рішення: розділити на доменні Facade.

Чи потрібен Facade в маленькому застосунку?

У застосунку з 1-2 екранами Facade зайвий — прямий виклик API та БД з UI простіший і зрозуміліший. Facade окуповується при 5+ екранах і 3+ підсистемах. У середніх і малих проєктах достатньо Repository як єдиного Facade-шару, без додаткової обгортки UseCase.

Як тестувати код, що використовує Facade?

Facade спрощує тестування, оскільки замінює цілу підсистему одним mock-об'єктом. Замість mock трьох компонентів (мережа + БД + аналітика) достатньо mock одного Facade. У Swift для цього використовують protocol, у Kotlin — interface. Facade також зручний для інтеграційних тестів, де перевіряється оркестрація компонентів.

Підсумки

  • Facade — структурний патерн, що надає простий інтерфейс до складної підсистеми
  • Service Layer і UseCase — поширені реалізації Facade в мобільній архітектурі
  • Facade не приховує підсистему: клієнт може звертатися до компонентів напряму за потреби
  • Facade vs Adapter: Facade спрощує, Adapter перетворює; Facade vs Mediator: Facade односторонній, Mediator двосторонній
  • God Facade — антипатерн: понад 15 методів в одному класі сигналізують про порушення Single Responsibility
  • Протокол/інтерфейс для Facade обов'язковий — це єдиний спосіб mock-тестування підсистеми
  • Рекомендація: вводьте Facade при 5+ екранах і 3+ підсистемах; для маленьких проєктів достатньо Repository

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також