Facade: những điều cơ bản về mẫu mặt tiền trong kiến trúc di động

Tác giả: IT Sectr Đã đăng: 2026-02-18 Thời gian đọc: 9 phút

Facade là một mẫu thiết kế cấu trúc cung cấp một giao diện đơn giản hóa cho một hệ thống con phức tạp của các lớp. Trong phát triển di động, Facade thường được triển khai dưới dạng Service Layer hoặc UseCase, che giấu sự tương tác với mạng, cơ sở dữ liệu và phân tích. Theo Martin Fowler (Patterns of Enterprise Application Architecture, 2003), Facade là một trong những mẫu chủ chốt để tổ chức tầng dịch vụ.

Điểm chính

  • Facade — mẫu cấu trúc cung cấp một giao diện đơn giản cho hệ thống phức tạp của các lớp, thư viện hoặc framework
  • Service Layer — triển khai Facade trong kiến trúc di động, che giấu API, bộ nhớ đệm và phân tích khỏi UI
  • Facade không che giấu hệ thống con — khách hàng có thể truy cập trực tiếp khi cần
  • UseCase trong Clean Architecture — một biến thể của Facade, điều phối một kịch bản nghiệp vụ duy nhất
  • Facade vs Adapter: Facade đơn giản hóa giao diện, Adapter chuyển đổi giao diện này sang giao diện khác

Mẫu Facade là gì?

Facade là một mẫu cấu trúc cung cấp một giao diện thống nhất cho một nhóm giao diện của hệ thống con. Nó định nghĩa một giao diện cấp cao giúp đơn giản hóa việc sử dụng hệ thống con. Facade không thêm chức năng mới — nó điều phối các thành phần hiện có, che giấu độ phức tạp trong tương tác của chúng khỏi khách hàng.

Kotlin
// Hệ thống con phức tạp
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 — một giao diện đơn giản cho 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 là một Facade che giấu AuthApi, UserDao và AnalyticsTracker khỏi ViewModel. UI gọi loginUser(email, password) thay vì ba yêu cầu riêng biệt tới API, cơ sở dữ liệu và phân tích. Điều này giảm độ liên kết: nếu ngày mai AuthApi trở thành FirebaseAuth hoặc UserDao chuyển sang Room, chỉ có Facade thay đổi, còn UI thì không.

Facade trong kiến trúc di động: Service Layer

Service Layer là một triển khai phổ biến của Facade trong các ứng dụng di động. Nó đóng gói logic nghiệp vụ và sự phối hợp giữa các tầng. Trong Android, Service Layer thường được triển khai qua UseCase (Clean Architecture), còn trong iOS qua các protocol Manager hoặc Service.

Thành phần Vai trò trong hệ thống con Điều Facade che giấu
AuthApi Yêu cầu mạng tới máy chủ Định dạng yêu cầu, endpoint, xử lý lỗi HTTP
UserDao Lưu trữ cục bộ token Lược đồ cơ sở dữ liệu, truy vấn SQL, di trú
AnalyticsTracker Gửi sự kiện phân tích Firebase/AppMetrica SDK, định dạng sự kiện
NetworkMonitor Kiểm tra khả năng truy cập mạng ConnectivityManager, BroadcastReceiver

AuthService kết hợp cả bốn thành phần. ViewModel gọi một phương thức duy nhất mà không biết rằng bên trong đang diễn ra yêu cầu mạng, ghi cơ sở dữ liệu, theo dõi và kiểm tra mạng. Khi kiểm thử, AuthService có thể được thay bằng mock, xác minh toàn bộ logic xác thực mà không cần tích hợp với các thành phần thực.

Facade vs Adapter vs Mediator

Facade, Adapter và Mediator là các mẫu cấu trúc, nhưng chúng giải quyết những bài toán khác nhau. Chúng thường bị nhầm lẫn vì cả ba đều đưa vào một đối tượng trung gian. Hãy phân tích sự khác biệt qua ví dụ một ứng dụng di động.

Khía cạnh Facade Adapter Mediator
Mục đích Đơn giản hóa giao diện hệ thống con Chuyển đổi một giao diện Giảm độ liên kết giữa các thành phần
Hướng Một giao diện → hệ thống con Khách hàng → Adaptee N thành phần ↔ Mediator
Thay đổi giao diện Tạo ra cái mới, đơn giản hóa Chuyển đổi cái hiện có Không thay đổi, chỉ điều phối
Hệ thống con có biết mẫu này không? Không Không Có, giao tiếp qua Mediator
Ví dụ trong phát triển di động UseCase / Service Layer RecyclerView.Adapter Coordinator trong iOS

Facade không che giấu hệ thống con — khách hàng có thể truy cập trực tiếp AuthApi khi cần. Adapter bắt buộc thay đổi giao diện của Adaptee. Mediator điều phối các tương tác phức tạp giữa nhiều đối tượng có thể không biết về nhau.

Triển khai Facade bằng Kotlin cho Android

Việc triển khai Facade bằng Kotlin cho Android với Clean Architecture sử dụng UseCase làm điểm vào cho mỗi kịch bản nghiệp vụ. UseCase là một Facade che giấu repository, mapper và các phụ thuộc khác khỏi tầng UI.

Kotlin
// Repository cũng là một Facade, nhưng ở cấp thấp hơn
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 cho kịch bản nghiệp vụ
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 là một Facade cho kịch bản tải hồ sơ. Nó che giấu logic bộ nhớ đệm (local → remote), ánh xạ DTO → Entity → Profile và theo dõi phân tích. ViewModel gọi invoke(userId) và nhận được UserProfile đã sẵn sàng hoặc một lỗi. UseCase có thể được kiểm thử độc lập bằng cách thay repository bằng một đối tượng mock.

Triển khai Facade bằng Swift cho iOS

Facade trong iOS thường được triển khai dưới dạng Manager hoặc Service. Khác với Android, iOS sử dụng protocol để định nghĩa giao diện Facade, giúp dễ dàng thay thế các triển khai trong kiểm thử. Hãy xem một Facade làm việc với phương tiện — tải, lưu bộ nhớ đệm và hiển thị.

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. Kiểm tra bộ nhớ đệm
        if let cached = cache.image(for: url) {
            return .success(cached)
        }
        // 2. Tải dữ liệu
        let result = await downloader.download(from: url)
        guard case let .success(data) = result else {
            return .failure(MediaError.downloadFailed)
        }
        // 3. Giải mã
        guard let image = decoder.decode(data) else {
            return .failure(MediaError.decodeFailed)
        }
        // 4. Lưu vào bộ nhớ đệm
        cache.setImage(image, for: url)
        return .success(image)
    }
}

MediaService đóng gói quy trình ba bước: bộ nhớ đệm → tải → giải mã. UI gọi một phương thức duy nhất loadImage(from:) thay vì quản lý ImageCache, URLSession và ImageDecoder. Khi kiểm thử, MediaServiceProtocol có thể được thay bằng mock trả về các ảnh định sẵn mà không cần tải thực tế.

Những lỗi điển hình khi sử dụng Facade

Những lỗi trong thiết kế Facade làm mất đi lợi ích của nó: thay vì đơn giản hóa, bạn nhận được một God Object mà toàn hệ thống phụ thuộc vào. Hãy phân tích ba vấn đề chính.

God Facade — quá nhiều trách nhiệm

Khi một Facade duy nhất chứa các phương thức xác thực, tải hồ sơ, gửi tin nhắn và đồng bộ hóa — đó là một God Object. Dấu hiệu: hơn 15 phương thức công khai trong một lớp. Giải pháp: chia nó thành nhiều Facade chuyên biệt theo các lĩnh vực trách nhiệm — AuthService, ProfileService, MessagingService.

Facade làm rò rỉ chi tiết hệ thống con

Nếu Facade trả về các kiểu đặc thù của hệ thống con (ví dụ, FirebaseUser hoặc RealmObject), khách hàng vẫn bị ràng buộc vào một triển khai cụ thể. Giải pháp: Facade chỉ nên trả về các kiểu của riêng nó (data class / struct), trừu tượng hóa hoàn toàn khách hàng khỏi chi tiết hệ thống con.

Facade như điểm vào duy nhất

Khi Facade cấm truy cập trực tiếp vào hệ thống con, nó trở thành nút thắt cổ chai. Đôi khi khách hàng cần một phương thức đặc thù của hệ thống con, và bắt họ phải đi qua Facade là thừa. Facade không nên là người gác cổng nghiêm ngặt: nó cung cấp một giao diện thuận tiện, nhưng không chặn truy cập trực tiếp vào các thành phần.

Các câu hỏi thường gặp

Sự khác biệt giữa Facade và Proxy là gì?

Facade cung cấp một giao diện đơn giản hóa cho hệ thống con, thường tạo ra một tập hợp phương thức mới. Proxy giữ nguyên giao diện giống như đối tượng gốc, nhưng thêm kiểm soát truy cập hoặc tải lười biếng. Facade dành cho việc đơn giản hóa, Proxy dành cho việc kiểm soát.

Facade có giống Service Layer không?

Service Layer là một triển khai của mẫu Facade ở cấp kiến trúc ứng dụng. Nó xác định ranh giới giữa UI và logic nghiệp vụ, che giấu chi tiết triển khai của các dịch vụ. Trong Android, Service Layer thường được triển khai qua UseCase; trong iOS — qua các protocol Manager hoặc Service.

Khi nào Facade trở thành God Object?

God Facade xuất hiện khi một lớp đảm nhận trách nhiệm của nhiều hệ thống con không liên quan. Dấu hiệu: hơn 15 phương thức công khai, các phương thức từ những lĩnh vực khác nhau (xác thực + thanh toán + thông báo), một lớp khó kiểm thử (hơn 10 phụ thuộc). Giải pháp: chia thành các Facade theo lĩnh vực.

Có cần Facade trong ứng dụng nhỏ không?

Trong một ứng dụng có 1-2 màn hình, Facade là thừa — gọi API và cơ sở dữ liệu trực tiếp từ UI đơn giản và rõ ràng hơn. Facade phát huy hiệu quả với 5+ màn hình và 3+ hệ thống con. Trong các dự án nhỏ và vừa, chỉ cần một Repository là tầng Facade duy nhất, không cần lớp bọc UseCase thêm.

Làm thế nào để kiểm thử mã sử dụng Facade?

Facade đơn giản hóa việc kiểm thử, vì nó thay thế toàn bộ hệ thống con bằng một đối tượng mock duy nhất. Thay vì mock ba thành phần (mạng + cơ sở dữ liệu + phân tích), chỉ cần mock một Facade. Trong Swift người ta dùng protocol cho việc này, trong Kotlin — interface. Facade cũng thuận tiện cho các bài kiểm thử tích hợp, nơi kiểm tra sự điều phối của các thành phần.

Tổng kết

  • Facade — mẫu cấu trúc cung cấp một giao diện đơn giản cho một hệ thống con phức tạp
  • Service LayerUseCase — những triển khai phổ biến của Facade trong kiến trúc di động
  • Facade không che giấu hệ thống con: khách hàng có thể truy cập trực tiếp vào các thành phần khi cần
  • Facade vs Adapter: Facade đơn giản hóa, Adapter chuyển đổi; Facade vs Mediator: Facade một chiều, Mediator hai chiều
  • God Facade — phản mẫu: hơn 15 phương thức trong một lớp báo hiệu vi phạm nguyên tắc Single Responsibility
  • Protocol/interface cho Facade là bắt buộc — đó là cách duy nhất để kiểm thử hệ thống con bằng mock
  • Khuyến nghị: đưa Facade vào khi có 5+ màn hình và 3+ hệ thống con; với dự án nhỏ, chỉ cần Repository

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm