Creación de Entidades y Repositorios en la Capa de Dominio en Android Studio

Clase 8 de 19Curso de Android: Modo Offline con Room y Realm

Resumen

La arquitectura de capas en Android es fundamental para desarrollar aplicaciones robustas y mantenibles. En este artículo, exploraremos cómo implementar la capa de dominio en una aplicación Android, creando entidades y repositorios que servirán como base para nuestra lógica de negocio. Esta capa es crucial ya que contiene las reglas de negocio independientes de cualquier framework o tecnología específica.

¿Cómo organizar la estructura de carpetas en Android Studio?

Antes de sumergirnos en la implementación de la capa de dominio, es importante organizar adecuadamente la estructura de nuestro proyecto. Una buena organización facilita la navegación y el mantenimiento del código a largo plazo.

Para mejorar la estructura, debemos:

  1. Mover la carpeta "data" a un nivel superior mediante refactorización.
  2. Crear un nuevo paquete llamado "domain" al mismo nivel que "data".

Esta organización sigue los principios de la arquitectura limpia (Clean Architecture), donde separamos claramente las responsabilidades de cada capa, facilitando así las pruebas y la escalabilidad del proyecto.

¿Cómo implementar las entidades en la capa de dominio?

Las entidades son el núcleo de nuestra aplicación y representan los objetos de negocio principales. En nuestro caso, implementaremos dos entidades: Order y PreOrder.

Creación de la entidad Order

La entidad Order representa una orden completa en nuestro sistema:

data class Order(
    val id: String,
    val customerName: String,
    val item: String,
    val total: Double,
    val imageUrl: String
)

Esta data class contiene todos los atributos necesarios para representar una orden:

  • id: Identificador único de la orden (String)
  • customerName: Nombre del cliente (String)
  • item: Nombre del producto (String)
  • total: Valor total de la orden (Double)
  • imageUrl: URL de la imagen asociada (String)

Creación de la entidad PreOrder

La entidad PreOrder representa órdenes que aún no han sido procesadas completamente:

data class PreOrder(
    val id: Long = 0,
    val customerName: String = "",
    val product: String = "",
    val isSend: Boolean = false
)

Observa que en esta entidad:

  • id es de tipo Long (a diferencia del String en Order)
  • Todos los campos tienen valores por defecto
  • Incluye un flag isSend para indicar si la preorden ha sido enviada

¿Cómo definir las interfaces de repositorio?

Los repositorios actúan como mediadores entre la capa de dominio y la capa de datos. Definimos interfaces para establecer contratos claros sobre cómo se accederá a los datos.

Interfaz OrderRepository

interface OrderRepository {
    fun getOrders(): Flow<Result<List<Order>>>
    suspend fun getOrderById(id: String): Result<Order?>
}

Esta interfaz define dos métodos principales:

  • getOrders(): Devuelve un Flow que emite un Result conteniendo una lista de órdenes
  • getOrderById(): Función suspendida que busca una orden específica por su ID

El uso de Flow nos permite observar cambios en la base de datos de manera reactiva, mientras que Result nos ayuda a manejar posibles errores durante la obtención de datos.

Interfaz PreOrderRepository

interface PreOrderRepository {
    suspend fun savePreOrder(preOrder: PreOrder): Result<Unit>
    fun getPreOrders(): Flow<Result<List<PreOrder>>>
    suspend fun deletePreOrder(id: Long): Unit
    suspend fun syncPreOrder(id: Long): Unit
}

Esta interfaz define cuatro operaciones principales:

  • savePreOrder(): Guarda una preorden en la base de datos local
  • getPreOrders(): Obtiene todas las preórdenes como un Flow observable
  • deletePreOrder(): Elimina una preorden por su ID
  • syncPreOrder(): Sincroniza una preorden específica con la API remota

Es importante notar que algunas funciones son suspend functions, lo que indica que deben ser llamadas desde un contexto de corrutina, mientras que las que devuelven Flow no necesitan ser suspendidas ya que Flow es inherentemente asíncrono.

¿Por qué es importante la capa de dominio en la arquitectura limpia?

La capa de dominio juega un papel crucial en la arquitectura de nuestra aplicación por varias razones:

  1. Independencia tecnológica: Las entidades y reglas de negocio no dependen de frameworks o bibliotecas específicas.
  2. Testabilidad mejorada: Al estar aislada, es más fácil escribir pruebas unitarias para esta capa.
  3. Mantenibilidad: Los cambios en otras capas (como UI o datos) no afectan directamente a la lógica de negocio.
  4. Claridad conceptual: Representa claramente los conceptos del dominio del problema que estamos resolviendo.

La implementación que hemos realizado establece una base sólida para el resto de la aplicación. En las próximas etapas, nos centraremos en el almacenamiento local para interactuar con la base de datos y completar la funcionalidad de nuestra aplicación.

¿Has implementado arquitectura por capas en tus proyectos Android? Comparte tu experiencia y cualquier duda que tengas sobre la implementación de la capa de dominio en los comentarios.