Facade adalah pola desain struktural yang menyediakan antarmuka yang disederhanakan ke subsistem kelas yang kompleks. Dalam pengembangan seluler, Facade paling sering diimplementasikan sebagai Service Layer atau UseCase, yang menyembunyikan interaksi dengan jaringan, basis data, dan analitik. Menurut Martin Fowler (Patterns of Enterprise Application Architecture, 2003), Facade adalah salah satu pola kunci untuk mengatur lapisan layanan.
Poin utama
Facade — pola struktural yang menyediakan antarmuka terpadu ke sekelompok antarmuka subsistem. Pola ini mendefinisikan antarmuka tingkat tinggi yang menyederhanakan penggunaan subsistem. Facade tidak menambah fungsionalitas baru — pola ini mengorkestrasi komponen yang ada, menyembunyikan kompleksitas interaksi mereka dari klien.
// Subsistem yang kompleks
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 — antarmuka sederhana untuk 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 yang menyembunyikan AuthApi, UserDao, dan AnalyticsTracker dari ViewModel. UI memanggil loginUser(email, password) alih-alih tiga permintaan terpisah ke API, basis data, dan analitik. Ini mengurangi keterikatan: jika besok AuthApi menjadi FirebaseAuth atau UserDao bermigrasi ke Room, hanya Facade yang berubah, bukan UI.
Service Layer — implementasi Facade yang umum di aplikasi seluler. Layer ini meng-enkapsulasi logika bisnis dan koordinasi antar lapisan. Di Android, Service Layer sering diimplementasikan melalui UseCase (Clean Architecture), di iOS — melalui Manager atau protokol Service.
| Komponen | Peran dalam subsistem | Apa yang disembunyikan Facade |
|---|---|---|
| AuthApi | Permintaan jaringan ke server | Format permintaan, endpoint, penanganan kesalahan HTTP |
| UserDao | Penyimpanan token secara lokal | Skema basis data, kueri SQL, migrasi |
| AnalyticsTracker | Pengiriman peristiwa analitik | SDK Firebase/AppMetrica, format peristiwa |
| NetworkMonitor | Memeriksa ketersediaan jaringan | ConnectivityManager, BroadcastReceiver |
AuthService menggabungkan keempat komponen. ViewModel memanggil satu metode, tanpa mengetahui bahwa di balik layar terjadi permintaan jaringan, penulisan ke basis data, pelacakan, dan pemeriksaan jaringan. Saat menguji, AuthService dapat diganti dengan mock, memeriksa seluruh logika autentikasi tanpa integrasi dengan komponen nyata.
Facade, Adapter, dan Mediator — pola struktural, tetapi memecahkan masalah yang berbeda. Mereka sering tertukar, karena ketiganya memperkenalkan objek perantara. Mari kita bahas perbedaannya dengan contoh aplikasi seluler.
| Aspek | Facade | Adapter | Mediator |
|---|---|---|---|
| Tujuan | Menyederhanakan antarmuka subsistem | Mengubah antarmuka | Mengurangi keterikatan komponen |
| Arah | Satu antarmuka → subsistem | Klien → Adaptee | N komponen ↔ Mediator |
| Perubahan antarmuka | Membuat yang baru, disederhanakan | Mengubah yang ada | Tidak mengubah, mengoordinasi |
| Apakah subsistem tahu tentang pola? | Tidak | Tidak | Ya, berkomunikasi melalui Mediator |
| Contoh dalam pengembangan seluler | UseCase / Service Layer | RecyclerView.Adapter | Coordinator di iOS |
Facade tidak menyembunyikan subsistem — klien dapat mengakses AuthApi secara langsung jika diperlukan. Adapter secara wajib mengubah antarmuka Adaptee. Mediator mengoordinasi interaksi kompleks antara banyak objek yang mungkin tidak saling mengenal.
Implementasi Facade di Kotlin untuk Android dengan Clean Architecture menggunakan UseCase sebagai titik masuk untuk setiap skenario bisnis. UseCase adalah Facade yang menyembunyikan repository, mapper, dan dependensi lain dari lapisan UI.
// Repository — juga Facade, tetapi satu tingkat lebih rendah
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 untuk skenario bisnis
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 untuk skenario pemuatan profil. Pola ini menyembunyikan logika caching (local → remote), pemetaan DTO → Entity → Profile, dan pelacakan analitik. ViewModel memanggil invoke(userId) dan menerima UserProfile yang siap atau sebuah kesalahan. UseCase dapat diuji secara terisolasi dengan mengganti repository dengan objek mock.
Facade di iOS sering diimplementasikan sebagai Manager atau Service. Berbeda dengan Android, iOS menggunakan protokol untuk mendefinisikan antarmuka Facade, yang memungkinkan penggantian implementasi dengan mudah dalam pengujian. Mari kita bahas Facade untuk bekerja dengan media — pemuatan, caching, dan penampilan.
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. Periksa cache
if let cached = cache.image(for: url) {
return .success(cached)
}
// 2. Muat data
let result = await downloader.download(from: url)
guard case let .success(data) = result else {
return .failure(MediaError.downloadFailed)
}
// 3. Dekode
guard let image = decoder.decode(data) else {
return .failure(MediaError.decodeFailed)
}
// 4. Simpan ke cache
cache.setImage(image, for: url)
return .success(image)
}
}MediaService meng-enkapsulasi proses tiga langkah: cache → pemuatan → decoding. UI memanggil satu metode loadImage(from:) alih-alih mengelola ImageCache, URLSession, dan ImageDecoder. Saat menguji, MediaServiceProtocol dapat diganti dengan mock yang mengembalikan gambar yang telah ditentukan tanpa pemuatan nyata.
Kesalahan dalam merancang Facade meniadakan keunggulannya: alih-alih penyederhanaan, muncul God Object yang membuat seluruh sistem bergantung padanya. Mari kita bahas tiga masalah utama.
Ketika satu Facade berisi metode untuk autentikasi, pemuatan profil, pengiriman pesan, dan sinkronisasi — ini adalah God Object. Tanda: lebih dari 15 metode publik dalam satu kelas. Solusi: membagi menjadi beberapa Facade khusus berdasarkan area tanggung jawab — AuthService, ProfileService, MessagingService.
Jika Facade mengembalikan tipe yang spesifik untuk subsistem (misalnya, FirebaseUser atau RealmObject), klien tetap terikat pada implementasi tertentu. Solusi: Facade harus mengembalikan hanya tipe miliknya sendiri (data class / struct), sepenuhnya mengabstraksi klien dari detail subsistem.
Ketika Facade melarang akses langsung ke subsistem, Facade menjadi penghambat. Terkadang klien membutuhkan metode spesifik dari subsistem, dan memaksanya melewati Facade adalah berlebihan. Facade tidak boleh menjadi gatekeeper yang ketat: Facade menyediakan antarmuka yang nyaman, tetapi tidak memblokir akses langsung ke komponen.
Pertanyaan yang sering diajukan
Facade menyediakan antarmuka yang disederhanakan ke subsistem, sering kali membuat serangkaian metode baru. Proxy mempertahankan antarmuka yang sama dengan objek asli, tetapi menambahkan kontrol akses atau lazy loading. Facade — untuk penyederhanaan, Proxy — untuk kontrol.
Service Layer — ini adalah implementasi pola Facade pada tingkat arsitektur aplikasi. Layer ini mendefinisikan batas antara UI dan logika bisnis, menyembunyikan detail implementasi layanan. Di Android, Service Layer sering diimplementasikan melalui UseCase, di iOS — melalui Manager atau protokol Service.
God Facade muncul ketika satu kelas mengambil tanggung jawab untuk beberapa subsistem yang tidak terkait. Tanda: lebih dari 15 metode publik, metode dari domain yang berbeda (autentikasi + pembayaran + notifikasi), kelas yang sulit diuji (lebih dari 10 dependensi). Solusi: membagi menjadi Facade domain.
Dalam aplikasi dengan 1-2 layar, Facade berlebihan — pemanggilan langsung API dan basis data dari UI lebih sederhana dan jelas. Facade terbayar dengan lebih dari 5 layar dan lebih dari 3 subsistem. Dalam proyek menengah dan kecil, Repository cukup sebagai satu-satunya lapisan Facade, tanpa pembungkus UseCase tambahan.
Facade menyederhanakan pengujian, karena menggantikan seluruh subsistem dengan satu objek mock. Alih-alih mock tiga komponen (jaringan + basis data + analitik), cukup mock satu Facade. Di Swift untuk ini digunakan protocol, di Kotlin — interface. Facade juga nyaman untuk pengujian integrasi, di mana orkestrasi komponen diperiksa.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga