Facade: fundamentos del patrón fachada en arquitectura móvil

Autor: IT Sectr Publicado: 2026-02-18 Tiempo de lectura: 9 min

Facade es un patrón de diseño estructural que proporciona una interfaz simplificada a un subsistema complejo de clases. En el desarrollo móvil, Facade se implementa con mayor frecuencia como Service Layer o UseCase, ocultando la interacción con la red, la base de datos y la analítica. Según Martin Fowler (Patterns of Enterprise Application Architecture, 2003), Facade es uno de los patrones clave para organizar la capa de servicios.

Lo esencial

  • Facade — patrón estructural que proporciona una interfaz simple a un sistema complejo de clases, bibliotecas o frameworks
  • Service Layer — implementación de Facade en arquitectura móvil que oculta la API, la caché y la analítica de la UI
  • Facade no oculta el subsistema — el cliente puede acceder a él directamente cuando lo necesite
  • UseCase en Clean Architecture — una variante de Facade que orquesta un único escenario de negocio
  • Facade vs Adapter: Facade simplifica la interfaz, Adapter transforma una interfaz en otra

¿Qué es el patrón Facade?

Facade es un patrón estructural que proporciona una interfaz unificada a un grupo de interfaces del subsistema. Define una interfaz de alto nivel que simplifica el uso del subsistema. Facade no agrega nueva funcionalidad — orquesta los componentes existentes, ocultando la complejidad de su interacción al cliente.

Kotlin
// Subsistema complejo
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 — una interfaz simple para la 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 es un Facade que oculta AuthApi, UserDao y AnalyticsTracker del ViewModel. La UI llama a loginUser(email, password) en lugar de tres solicitudes separadas a la API, la base de datos y la analítica. Esto reduce el acoplamiento: si mañana AuthApi se convierte en FirebaseAuth o UserDao migra a Room, solo cambia el Facade, no la UI.

Facade en arquitectura móvil: Service Layer

Service Layer es una implementación común de Facade en aplicaciones móviles. Encapsula la lógica de negocio y la coordinación entre capas. En Android, el Service Layer a menudo se implementa mediante UseCase (Clean Architecture), y en iOS mediante protocolos Manager o Service.

Componente Rol en el subsistema Qué oculta Facade
AuthApi Solicitud de red al servidor Formato de la solicitud, endpoint, manejo de errores HTTP
UserDao Almacenamiento local del token Esquema de la base de datos, consultas SQL, migraciones
AnalyticsTracker Envío de eventos de analítica SDK de Firebase/AppMetrica, formato de eventos
NetworkMonitor Comprobación de disponibilidad de red ConnectivityManager, BroadcastReceiver

AuthService combina los cuatro componentes. El ViewModel llama a un único método sin saber que debajo hay una solicitud de red, una escritura en la base de datos, un seguimiento y una comprobación de red. Al probar, AuthService puede reemplazarse por un mock, verificando toda la lógica de autenticación sin integración con componentes reales.

Facade vs Adapter vs Mediator

Facade, Adapter y Mediator son patrones estructurales, pero resuelven problemas distintos. A menudo se confunden, ya que los tres introducen un objeto intermediario. Analicemos las diferencias con el ejemplo de una aplicación móvil.

Aspecto Facade Adapter Mediator
Objetivo Simplificar la interfaz del subsistema Transformar una interfaz Reducir el acoplamiento entre componentes
Dirección Una interfaz → subsistema Cliente → Adaptee N componentes ↔ Mediator
Cambio de interfaz Crea una nueva, simplificada Transforma la existente No la cambia, coordina
¿El subsistema conoce el patrón? No No Sí, se comunica a través de Mediator
Ejemplo en desarrollo móvil UseCase / Service Layer RecyclerView.Adapter Coordinator en iOS

Facade no oculta el subsistema — el cliente puede acceder a AuthApi directamente cuando lo necesite. Adapter cambia obligatoriamente la interfaz del Adaptee. Mediator coordina interacciones complejas entre muchos objetos que pueden no conocerse entre sí.

Implementación de Facade en Kotlin para Android

La implementación de Facade en Kotlin para Android con Clean Architecture usa UseCase como punto de entrada para cada escenario de negocio. UseCase es un Facade que oculta el repositorio, el mapeador y otras dependencias de la capa UI.

Kotlin
// Repository también es un Facade, pero de nivel inferior
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 — un Facade para el escenario de negocio
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 es un Facade para el escenario de carga de perfil. Oculta la lógica de caché (local → remoto), el mapeo DTO → Entity → Profile y el seguimiento de analítica. El ViewModel llama a invoke(userId) y recibe un UserProfile listo o un error. El UseCase puede probarse de forma aislada, reemplazando el repositorio por un mock.

Implementación de Facade en Swift para iOS

Facade en iOS a menudo se implementa como Manager o Service. A diferencia de Android, iOS usa protocolos para definir la interfaz del Facade, lo que permite reemplazar fácilmente las implementaciones en las pruebas. Veamos un Facade para trabajar con medios: carga, caché y visualización.

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. Comprobar la caché
        if let cached = cache.image(for: url) {
            return .success(cached)
        }
        // 2. Cargar los datos
        let result = await downloader.download(from: url)
        guard case let .success(data) = result else {
            return .failure(MediaError.downloadFailed)
        }
        // 3. Decodificar
        guard let image = decoder.decode(data) else {
            return .failure(MediaError.decodeFailed)
        }
        // 4. Guardar en la caché
        cache.setImage(image, for: url)
        return .success(image)
    }
}

MediaService encapsula un proceso de tres pasos: caché → carga → decodificación. La UI llama a un único método loadImage(from:) en lugar de gestionar ImageCache, URLSession e ImageDecoder. Al probar, se puede reemplazar MediaServiceProtocol por un mock que devuelve imágenes preestablecidas sin carga real.

Errores típicos al usar Facade

Los errores al diseñar Facade anulan sus ventajas: en lugar de simplificar, se obtiene un God Object del que depende todo el sistema. Analicemos los tres problemas principales.

God Facade — demasiada responsabilidad

Cuando un único Facade contiene métodos para autorización, carga de perfil, envío de mensajes y sincronización — esto es un God Object. Señal: más de 15 métodos públicos en una clase. Solución: dividirlo en varios Facade especializados por áreas de responsabilidad — AuthService, ProfileService, MessagingService.

Facade con fuga de detalles del subsistema

Si el Facade devuelve tipos específicos del subsistema (por ejemplo, FirebaseUser o RealmObject), el cliente sigue ligado a una implementación concreta. Solución: el Facade debe devolver solo sus propios tipos (data class / struct), abstrayendo por completo al cliente de los detalles del subsistema.

Facade como único punto de entrada

Cuando el Facade prohíbe el acceso directo al subsistema, se convierte en un cuello de botella. A veces el cliente necesita un método específico del subsistema, y obligarlo a pasar por el Facade es redundante. Facade no debe ser un gatekeeper estricto: proporciona una interfaz cómoda, pero no bloquea el acceso directo a los componentes.

Preguntas frecuentes

¿Cuál es la diferencia entre Facade y Proxy?

Facade proporciona una interfaz simplificada al subsistema, a menudo creando un nuevo conjunto de métodos. Proxy conserva la misma interfaz que el objeto original, pero agrega control de acceso o carga diferida. Facade es para simplificar, Proxy para controlar.

¿Facade es lo mismo que Service Layer?

Service Layer es una implementación del patrón Facade a nivel de arquitectura de la aplicación. Define el límite entre la UI y la lógica de negocio, ocultando los detalles de implementación de los servicios. En Android, el Service Layer a menudo se implementa mediante UseCase; en iOS, mediante protocolos Manager o Service.

¿Cuándo Facade se convierte en God Object?

God Facade surge cuando una clase asume la responsabilidad de varios subsistemas no relacionados. Señales: más de 15 métodos públicos, métodos de distintos dominios (autorización + pagos + notificaciones), una clase difícil de probar (más de 10 dependencias). Solución: dividir en Facade de dominio.

¿Se necesita Facade en una aplicación pequeña?

En una aplicación con 1-2 pantallas, Facade es redundante — llamar a la API y a la base de datos directamente desde la UI es más simple y claro. Facade se amortiza con 5+ pantallas y 3+ subsistemas. En proyectos pequeños y medianos basta con un Repository como única capa Facade, sin envoltura adicional de UseCase.

¿Cómo probar código que usa Facade?

Facade simplifica las pruebas, ya que reemplaza todo un subsistema por un único mock. En lugar de simular tres componentes (red + base de datos + analítica), basta con simular un Facade. En Swift se usan protocolos para esto; en Kotlin, interfaces. Facade también es conveniente para pruebas de integración que verifican la orquestación de componentes.

Resumen

  • Facade — patrón estructural que proporciona una interfaz simple a un subsistema complejo
  • Service Layer y UseCase — implementaciones comunes de Facade en arquitectura móvil
  • Facade no oculta el subsistema: el cliente puede acceder a los componentes directamente cuando lo necesite
  • Facade vs Adapter: Facade simplifica, Adapter transforma; Facade vs Mediator: Facade es unidireccional, Mediator es bidireccional
  • God Facade — antipatrón: más de 15 métodos en una clase señalan la violación de Single Responsibility
  • Protocolo/interfaz para Facade es obligatorio — es la única forma de probar el subsistema con mocks
  • Recomendación: introduce Facade con 5+ pantallas y 3+ subsistemas; para proyectos pequeños basta con Repository

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también