Facade je strukturální návrhový vzor, který poskytuje zjednodušené rozhraní ke složitému subsystému tříd. V mobilním vývoji se Facade nejčastěji implementuje jako Service Layer nebo UseCase, který skrývá interakci se sítí, databází a analytikou. Podle Martina Fowlera (Patterns of Enterprise Application Architecture, 2003) je Facade jedním z klíčových vzorů pro organizaci servisní vrstvy.
Hlavní body
Facade — strukturální vzor, který poskytuje jednotné rozhraní ke skupině rozhraní subsystému. Definuje rozhraní na vysoké úrovni, které zjednodušuje použití subsystému. Facade nepřidává novou funkcionalitu — orchestruje stávající komponenty a skrývá složitost jejich vzájemné interakce před klientem.
// Složitý subsystém
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 — jednoduché rozhraní pro 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, který skrývá AuthApi, UserDao a AnalyticsTracker před ViewModel. UI volá loginUser(email, password) místo tří samostatných požadavků na API, databázi a analytiku. To snižuje provázanost: pokud se zítra AuthApi stane FirebaseAuth nebo UserDao migruje na Room, změní se pouze Facade, ne UI.
Service Layer — rozšířená implementace vzoru Facade v mobilních aplikacích. Zapouzdřuje obchodní logiku a koordinaci mezi vrstvami. V systému Android se Service Layer často implementuje přes UseCase (Clean Architecture), v systému iOS — přes Manager nebo protokoly Service.
| Komponenta | Role v subsystému | Co Facade skrývá |
|---|---|---|
| AuthApi | Síťový požadavek na server | Formát požadavku, endpoint, zpracování chyb HTTP |
| UserDao | Lokální ukládání tokenu | Schéma databáze, SQL dotazy, migrace |
| AnalyticsTracker | Odesílání událostí analytiky | SDK Firebase/AppMetrica, formát událostí |
| NetworkMonitor | Kontrola dostupnosti sítě | ConnectivityManager, BroadcastReceiver |
AuthService spojuje všechny čtyři komponenty. ViewModel volá jednu metodu, aniž by věděl, že pod kapotou probíhá síťový požadavek, zápis do databáze, sledování a kontrola sítě. Při testování lze AuthService nahradit mockem a ověřit celou logiku autentizace bez integrace se skutečnými komponentami.
Facade, Adapter a Mediator — strukturální vzory, ale řeší různé úkoly. Často se zaměňují, protože všechny tři zavádějí zprostředkující objekt. Rozebereme rozdíly na příkladu mobilní aplikace.
| Aspekt | Facade | Adapter | Mediator |
|---|---|---|---|
| Cíl | Zjednodušit rozhraní subsystému | Převést rozhraní | Snížit provázanost komponent |
| Směr | Jedno rozhraní → subsystém | Klient → Adaptee | N komponent ↔ Mediator |
| Změna rozhraní | Vytváří nové, zjednodušené | Převádí stávající | Nemění, koordinuje |
| Ví subsystém o vzoru? | Ne | Ne | Ano, komunikuje přes Mediator |
| Příklad v mobilním vývoji | UseCase / Service Layer | RecyclerView.Adapter | Coordinator v systému iOS |
Facade neskrývá subsystém — klient může v případě potřeby přistupovat přímo k AuthApi. Adapter povinně mění rozhraní Adaptee. Mediator koordinuje složité interakce mezi mnoha objekty, které se navzájem nemusí znát.
Implementace vzoru Facade v Kotlin pro Android s Clean Architecture používá UseCase jako vstupní bod pro každý obchodní scénář. UseCase je Facade, který skrývá repozitář, mapper a další závislosti před vrstvou UI.
// Repository — také Facade, ale o úroveň níže
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 pro obchodní scénář
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 pro scénář načítání profilu. Skrývá logiku cachování (local → remote), mapování DTO → Entity → Profile a sledování analytiky. ViewModel volá invoke(userId) a dostává hotový UserProfile nebo chybu. UseCase lze testovat izolovaně, když repozitář nahradíme mock objektem.
Facade v systému iOS se často implementuje jako Manager nebo Service. Na rozdíl od systému Android používá iOS protokoly pro definování rozhraní vzoru Facade, což umožňuje snadno nahrazovat implementace v testech. Probereme Facade pro práci s médii — načítání, cachování a zobrazování.
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. Zkontrolovat cache
if let cached = cache.image(for: url) {
return .success(cached)
}
// 2. Načíst data
let result = await downloader.download(from: url)
guard case let .success(data) = result else {
return .failure(MediaError.downloadFailed)
}
// 3. Dekódovat
guard let image = decoder.decode(data) else {
return .failure(MediaError.decodeFailed)
}
// 4. Uložit do cache
cache.setImage(image, for: url)
return .success(image)
}
}MediaService zapouzdřuje tříkrokový proces: cache → načtení → dekódování. UI volá jednu metodu loadImage(from:) místo správy ImageCache, URLSession a ImageDecoder. Při testování lze MediaServiceProtocol nahradit mockem, který vrací přednastavené obrázky bez skutečného načítání.
Chyby při návrhu vzoru Facade ničí jeho výhody: místo zjednodušení vzniká God Object, na kterém závisí celý systém. Probereme tři hlavní problémy.
Když jeden Facade obsahuje metody pro autentizaci, načítání profilu, odesílání zpráv a synchronizaci — to je God Object. Znak: více než 15 veřejných metod v jedné třídě. Řešení: rozdělit na několik specializovaných vzorů Facade podle oblastí odpovědnosti — AuthService, ProfileService, MessagingService.
Pokud Facade vrací typy specifické pro subsystém (například FirebaseUser nebo RealmObject), klient je stále vázán na konkrétní implementaci. Řešení: Facade by měl vracet pouze vlastní typy (data class / struct), čímž klienta zcela abstrahuje od detailů subsystému.
Když Facade zakazuje přímý přístup k subsystému, stává se úzkým hrdlem. Někdy klient potřebuje specifickou metodu subsystému a nutit ho procházet přes Facade je zbytečné. Facade by neměl být přísný gatekeeper: poskytuje pohodlné rozhraní, ale neblokuje přímý přístup ke komponentám.
Často kladené dotazy
Facade poskytuje zjednodušené rozhraní k subsystému a často vytváří novou sadu metod. Proxy zachovává stejné rozhraní jako původní objekt, ale přidává kontrolu přístupu nebo líné načítání. Facade — pro zjednodušení, Proxy — pro kontrolu.
Service Layer — to je implementace vzoru Facade na úrovni architektury aplikace. Definuje hranici mezi UI a obchodní logikou a skrývá detaily implementace služeb. V systému Android se Service Layer často implementuje přes UseCase, v systému iOS — přes Manager nebo protokoly Service.
God Facade vzniká, když jedna třída přebírá odpovědnost za několik nesouvisejících subsystémů. Znaky: více než 15 veřejných metod, metody z různých domén (autentizace + platby + oznámení), třída, kterou je obtížné testovat (více než 10 závislostí). Řešení: rozdělit na doménové vzory Facade.
V aplikaci s 1-2 obrazovkami je Facade zbytečný — přímé volání API a databáze z UI je jednodušší a přehlednější. Facade se vyplatí při více než 5 obrazovkách a více než 3 subsystémech. Ve středních a malých projektech stačí Repository jako jediná vrstva Facade, bez dodatečného obalu UseCase.
Facade zjednodušuje testování, protože nahrazuje celý subsystém jedním mock objektem. Místo mockování tří komponent (síť + databáze + analytika) stačí mock jednoho vzoru Facade. Ve Swift se k tomu používá protocol, v Kotlin — interface. Facade je také vhodný pro integrační testy, kde se ověřuje orchestrace komponent.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také