Facade, karmaşık bir sınıf alt sistemine basitleştirilmiş bir arayüz sağlayan yapısal bir tasarım desenidir. Mobil geliştirmede Facade, ağ, veritabanı ve analitik ile etkileşimi gizleyen bir Service Layer veya UseCase olarak en sık uygulanır. Martin Fowler'a göre (Patterns of Enterprise Application Architecture, 2003), Facade hizmet katmanını organize etmek için kilit desenlerden biridir.
Önemli noktalar
Facade, alt sistem arayüzleri grubuna birleşik bir arayüz sağlayan yapısal bir desendir. Alt sistemin kullanımını basitleştiren üst düzey bir arayüz tanımlar. Facade yeni işlevsellik eklemez — mevcut bileşenleri orkestra eder ve etkileşimlerinin karmaşıklığını istemciden gizler.
// Karmaşık alt sistem
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 için basit bir arayüz
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, AuthApi, UserDao ve AnalyticsTracker'ı ViewModel'den gizleyen bir Facade'dir. UI, API'ye, veritabanına ve analitiğe üç ayrı istek yerine loginUser(email, password) çağırır. Bu, bağımlılığı azaltır: yarın AuthApi FirebaseAuth olursa veya UserDao Room'a taşınırsa, yalnızca Facade değişir, UI değişmez.
Service Layer, mobil uygulamalarda Facade'in yaygın bir uygulamasıdır. İş mantığını ve katmanlar arasındaki koordinasyonu kapsüller. Android'de Service Layer genellikle UseCase (Clean Architecture) ile, iOS'ta ise Manager veya Service protokolleriyle uygulanır.
| Bileşen | Alt sistemdeki rolü | Facade neyi gizler |
|---|---|---|
| AuthApi | Sunucuya ağ isteği | İstek formatı, endpoint, HTTP hata işleme |
| UserDao | Token'ın yerel depolanması | Veritabanı şeması, SQL sorguları, geçişler |
| AnalyticsTracker | Analitik olaylarının gönderimi | Firebase/AppMetrica SDK, olay formatı |
| NetworkMonitor | Ağ kullanılabilirliği kontrolü | ConnectivityManager, BroadcastReceiver |
AuthService dört bileşenin tümünü birleştirir. ViewModel, arka planda bir ağ isteği, veritabanı yazma, izleme ve ağ kontrolü gerçekleştiğini bilmeden tek bir yöntem çağırır. Test ederken, AuthService bir mock ile değiştirilerek gerçek bileşenlerle entegrasyon olmadan tüm kimlik doğrulama mantığı doğrulanabilir.
Facade, Adapter ve Mediator yapısal desenlerdir, ancak farklı sorunları çözerler. Üçü de bir aracı nesne sunduğu için sık sık karıştırılırlar. Farklılıkları bir mobil uygulama örneği üzerinden analiz edelim.
| Yön | Facade | Adapter | Mediator |
|---|---|---|---|
| Amaç | Alt sistem arayüzünü basitleştirmek | Bir arayüzü dönüştürmek | Bileşenler arası bağımlılığı azaltmak |
| Yön | Bir arayüz → alt sistem | İstemci → Adaptee | N bileşen ↔ Mediator |
| Arayüz değişimi | Yeni, basitleştirilmiş bir tane oluşturur | Mevcut olanı dönüştürür | Değiştirmez, koordine eder |
| Alt sistem deseni biliyor mu? | Hayır | Hayır | Evet, Mediator üzerinden iletişim kurar |
| Mobil geliştirmede örnek | UseCase / Service Layer | RecyclerView.Adapter | iOS'ta Coordinator |
Facade alt sistemi gizlemez — istemci gerektiğinde AuthApi'ye doğrudan erişebilir. Adapter zorunlu olarak Adaptee'nin arayüzünü değiştirir. Mediator, birbirini tanımayabilecek birçok nesne arasındaki karmaşık etkileşimleri koordine eder.
Facade uygulaması, Kotlin'de Android için Clean Architecture ile her iş senaryosu için giriş noktası olarak UseCase kullanır. UseCase, depoyu, dönüştürücüyü ve diğer bağımlılıkları UI katmanından gizleyen bir Facade'dir.
// Repository de bir Facade'dir, ancak daha alt düzeyde
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 — iş senaryosu için bir 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, profil yükleme senaryosu için bir Facade'dir. Önbellekleme mantığını (local → remote), DTO → Entity → Profile dönüşümünü ve analitik takibini gizler. ViewModel invoke(userId) çağırır ve hazır bir UserProfile veya bir hata alır. UseCase, depoyu bir mock nesnesiyle değiştirerek izole bir şekilde test edilebilir.
iOS'ta Facade genellikle Manager veya Service olarak uygulanır. Android'in aksine, iOS Facade arayüzünü tanımlamak için protokoller kullanır; bu da testlerde uygulamaların kolayca değiştirilmesini sağlar. Medya ile çalışan bir Facade'e bakalım — yükleme, önbelleğe alma ve görüntüleme.
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. Önbelleği kontrol et
if let cached = cache.image(for: url) {
return .success(cached)
}
// 2. Verileri yükle
let result = await downloader.download(from: url)
guard case let .success(data) = result else {
return .failure(MediaError.downloadFailed)
}
// 3. Kodu çöz
guard let image = decoder.decode(data) else {
return .failure(MediaError.decodeFailed)
}
// 4. Önbelleğe kaydet
cache.setImage(image, for: url)
return .success(image)
}
}MediaService üç adımlı bir süreci kapsüller: önbellek → yükleme → kod çözme. UI, ImageCache, URLSession ve ImageDecoder'ı yönetmek yerine tek bir yöntem loadImage(from:) çağırır. Test ederken, MediaServiceProtocol gerçek yükleme olmadan önceden belirlenmiş görseller döndüren bir mock ile değiştirilebilir.
Hatalar, Facade tasarımında avantajlarını boşa çıkarır: basitleştirme yerine tüm sistemin bağımlı olduğu bir God Object elde edilir. Üç ana sorunu analiz edelim.
Tek bir Facade kimlik doğrulama, profil yükleme, mesaj gönderme ve senkronizasyon yöntemleri içerdiğinde — bu bir God Object'tir. Belirti: bir sınıfta 15+ genel yöntem. Çözüm: sorumluluk alanlarına göre birkaç uzmanlaşmış Facade'e bölün — AuthService, ProfileService, MessagingService.
Facade alt sisteme özgü türler döndürürse (örneğin, FirebaseUser veya RealmObject), istemci yine de belirli bir uygulamaya bağlı kalır. Çözüm: Facade yalnızca kendi türlerini (data class / struct) döndürmeli, istemciyi alt sistem detaylarından tamamen soyutlamalıdır.
Facade alt sisteme doğrudan erişimi yasakladığında, darboğaz haline gelir. Bazen istemcinin alt sistemin belirli bir yöntemine ihtiyacı olur ve onu Facade'den geçmeye zorlamak gereksizdir. Facade katı bir kapı bekçisi olmamalıdır: uygun bir arayüz sağlar, ancak bileşenlere doğrudan erişimi engellemez.
Sık sorulan sorular
Facade alt sisteme basitleştirilmiş bir arayüz sağlar ve genellikle yeni bir yöntem seti oluşturur. Proxy orijinal nesneyle aynı arayüzü korur, ancak erişim kontrolü veya tembel yükleme ekler. Facade basitleştirme için, Proxy kontrol içindir.
Service Layer, uygulama mimarisi düzeyinde Facade deseninin bir uygulamasıdır. UI ile iş mantığı arasındaki sınırı tanımlar ve hizmetlerin uygulama detaylarını gizler. Android'de Service Layer genellikle UseCase ile; iOS'ta Manager veya Service protokolleriyle uygulanır.
God Facade, bir sınıfın birbiriyle ilgisiz birden çok alt sistemin sorumluluğunu üstlenmesiyle ortaya çıkar. Belirtiler: 15+ genel yöntem, farklı alanlardan yöntemler (kimlik doğrulama + ödemeler + bildirimler), test edilmesi zor bir sınıf (10+ bağımlılık). Çözüm: alan bazlı Facade'lere bölün.
1-2 ekranlı bir uygulamada Facade gereksizdir — API ve veritabanını UI'dan doğrudan çağırmak daha basit ve anlaşılırdır. Facade kendini amorti eder 5+ ekran ve 3+ alt sistemde. Küçük ve orta ölçekli projelerde, ek UseCase sarmalayıcısı olmadan tek Facade katmanı olarak bir Repository yeterlidir.
Facade test etmeyi basitleştirir, çünkü tüm bir alt sistemi tek bir mock nesnesiyle değiştirir. Üç bileşeni (ağ + veritabanı + analitik) mock'lamak yerine tek bir Facade'i mock'lamak yeterlidir. Swift'te bunun için protokoller, Kotlin'de ise interface'ler kullanılır. Facade, bileşen orkestrasyonunu doğrulayan entegrasyon testleri için de uygundur.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun