Swift Academy · Lección

Patrones de casos de uso y repositorios

Defina casos de uso como protocolos de Swift e implemente interfaces de repositorio.

Lección 2 de 413 pasos

Patrones de casos de uso y repositorios es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué es un caso de uso?

Un caso de uso (interactor) encapsula una única acción de negocio y coordina las entidades de dominio y los repositorios.

struct PlaceOrderUseCase {
  let cart: CartRepository
  let payment: PaymentService
  let orders: OrderRepository
  func execute(userId: Int) async throws -> Order {
    let items = try await cart.items(for: userId)
    let receipt = try await payment.charge(items: items)
    return try await orders.create(receipt: receipt)
  }
}

Responsabilidad única

Cada caso de uso hace exactamente una cosa. Varias responsabilidades significan varios casos de uso.

// One use case per business action:
struct FetchUserUseCase { ... }
struct UpdateUserUseCase { ... }
struct DeleteUserUseCase { ... }

El caso de uso como protocolo

Defina un protocolo para el caso de uso de modo que pueda simularlo en las pruebas de la capa de presentación.

protocol PlacingOrder {
  func execute(userId: Int) async throws -> Order
}
struct PlaceOrderUseCase: PlacingOrder { ... }

¿Qué es un repositorio?

Un repositorio abstrae la fuente de datos. Los consumidores interactúan con un protocolo de Swift; la implementación puede usar la red, Core Data o memoria.

protocol OrderRepository {
  func create(receipt: PaymentReceipt) async throws -> Order
  func list(userId: Int) async throws -> [Order]
  func cancel(orderId: Int) async throws
}

Implementación del repositorio

El repositorio concreto traduce las llamadas del dominio en operaciones de red o de base de datos.

struct RemoteOrderRepository: OrderRepository {
  func create(receipt: PaymentReceipt) async throws -> Order {
    let dto = receipt.toDTO()
    let data = try await api.post("/orders", body: dto)
    return try JSONDecoder().decode(OrderDTO.self, from: data).toDomain()
  }
  func list(userId: Int) async throws -> [Order] { ... }
  func cancel(orderId: Int) async throws { ... }
}

Repositorio en memoria para pruebas

Proporcione un repositorio en memoria para realizar pruebas rápidas y deterministas sin operaciones de E/S.

final class InMemoryOrderRepo: OrderRepository {
  var orders: [Order] = []
  func create(receipt: PaymentReceipt) async throws -> Order {
    let order = Order(id: orders.count + 1, items: receipt.items)
    orders.append(order)
    return order
  }
  func list(userId: Int) async throws -> [Order] { orders }
  func cancel(orderId: Int) async throws { orders.removeAll { $0.id == orderId } }
}

Composición de casos de uso

Los casos de uso pueden llamar a otros casos de uso para compartir suboperaciones y mantener el enfoque de cada uno.

struct CheckoutUseCase {
  let validateCart: ValidateCartUseCase
  let placeOrder: PlaceOrderUseCase
  let notifyUser: NotifyUserUseCase
  func execute(userId: Int) async throws -> Order {
    try await validateCart.execute(userId: userId)
    let order = try await placeOrder.execute(userId: userId)
    try await notifyUser.execute(order: order)
    return order
  }
}

Repositorio frente a servicio

Repositorio: operaciones CRUD sobre un único tipo de entidad. Servicio: coordina varias entidades o llama a API externas sin encargarse directamente del almacenamiento.

// Repository: single entity
protocol UserRepository { func getUser(id: Int) async throws -> User }
// Service: cross-entity operation
protocol AuthService { func login(email: String, password: String) async throws -> Session }

Almacenamiento en caché en los repositorios

Los repositorios pueden almacenar los resultados en caché de forma transparente sin que el caso de uso conozca ese detalle de implementación.

struct CachedUserRepository: UserRepository {
  private var cache: [Int: User] = [:]
  private let remote: UserRepository
  func getUser(id: Int) async throws -> User {
    if let cached = cache[id] { return cached }
    let user = try await remote.getUser(id: id)
    cache[id] = user
    return user
  }
  func saveUser(_ user: User) async throws { try await remote.saveUser(user) }
}

Facilidad de prueba

Como los casos de uso dependen de repositorios definidos mediante protocolos, puede inyectar stubs para probar la lógica de negocio de forma aislada.

let repo = InMemoryOrderRepo()
let sut = PlaceOrderUseCase(orders: repo, ...)
let order = try await sut.execute(userId: 1)
XCTAssertEqual(repo.orders.count, 1)

Traducción de errores

Los repositorios deben traducir los errores de la capa de datos (red o base de datos) a errores del dominio antes de devolverlos.

func getUser(id: Int) async throws -> User {
  do {
    let data = try await api.get("/users/\(id)")
    return try decode(data)
  } catch let e as URLError where e.code == .notConnectedToInternet {
    throw DomainError.offline
  }
}

Comprobación rápida

¿Cuál es la diferencia principal entre un repositorio y un servicio en la arquitectura limpia?

Resumen de la lección

Los casos de uso encapsulan acciones de negocio individuales y dependen de protocolos de repositorio. Los repositorios abstraen las fuentes de datos mediante un protocolo. Use repositorios en memoria para realizar pruebas rápidas. Los repositorios traducen los errores de infraestructura a errores del dominio. Los servicios coordinan operaciones que involucran varias entidades.

Gratis para empezar

Aprende Swift con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
122
Lecciones
409

Preguntas frecuentes

¿La lección «Patrones de casos de uso y repositorios» es gratis?

Sí — el texto completo de «Patrones de casos de uso y repositorios» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Patrones de casos de uso y repositorios»?

Defina casos de uso como protocolos de Swift e implemente interfaces de repositorio. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Swift Academy?

No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Patrones de casos de uso y repositorios»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Swift Academy?

Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Capas: dominio, datos y presentación
  2. Patrones de casos de uso y repositorios
  3. Inversión de dependencias con abstracciones de protocolos
  4. Integración de capas sin un framework de DI
← Volver a Swift Academy