โ Back to Design Patterns
๐๏ธ
Structural
Facade
Provides a simplified interface to a complex subsystem, hiding its internals.
The Problem
A complex library or set of services has many classes, configurations, and entry points. Client code becomes tangled managing all of them directly.
How It Works
- โบReduces coupling between client and complex subsystem
- โบDoesn't seal the subsystem โ advanced users can bypass the facade when needed
- โบSingle entry point makes the subsystem easier to use correctly
- โบSimplifies testing โ you can mock the facade instead of every subsystem class
- โบCommon when wrapping third-party SDKs to limit exposure to your app
When to Use
โSimplifying a complex library or set of services behind one clean interface
โLayering subsystems to reduce dependencies between them
โProviding sensible defaults for the common case
โWrapping a third-party SDK so your app is not tightly coupled to it
Real-World Examples
๐
iOS
Alamofire (facade over URLSession stack), AVPlayer wrapper classes
๐ค
Android
Glide/Picasso (facade over Bitmap/network ops), Retrofit
๐
Web
jQuery (facade over DOM APIs), axios (facade over XMLHttpRequest/fetch)
Code Examples
Swift
// Complex subsystems
class AuthService {
func login(user: String, pass: String) -> String { "token_abc" }
}
class ProfileService {
func fetch(token: String) -> [String: String] { ["name": "Agus"] }
}
class CacheService {
func store(_ key: String, _ value: Any) { }
}
// Facade: one entry point for the whole auth + profile flow
class AppFacade {
private let auth = AuthService()
private let profile = ProfileService()
private let cache = CacheService()
func signIn(username: String, password: String) -> [String: String] {
let token = auth.login(user: username, pass: password)
let data = profile.fetch(token: token)
cache.store("profile", data)
return data
}
}
// Client only deals with one object
let app = AppFacade()
print(app.signIn(username: "agus", password: "secret"))
// ["name": "Agus"]