0Pricing
Swift Academy · 课时

用例与仓储模式

将用例定义为 Swift 协议,并实现仓储接口。

用例与仓储模式 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

什么是用例

用例(交互器)封装单项业务操作,并协调领域实体和仓储。

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)
  }
}

单一职责

每个用例只完成一件事。多个职责意味着需要多个用例。

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

将用例定义为协议

为用例定义协议,这样就可以在表现层测试中对其进行模拟。

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

什么是仓储

仓储对数据源进行抽象。调用方通过 Swift 协议与其交互;具体实现可以使用网络、Core Data 或内存数据。

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

仓储实现

具体仓储将领域调用转换为网络或数据库操作。

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 { ... }
}

用于测试的内存仓储

提供内存仓储,以便在不进行输入输出操作的情况下执行快速且确定的测试。

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 } }
}

组合用例

用例可以调用其他用例来执行共享的子操作,同时保持各自职责单一。

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
  }
}

仓储与服务的区别

仓储:对单一实体类型执行增删改查。服务:协调多个实体,或调用外部接口,但不直接负责存储。

// 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 }

仓储中的缓存

仓储可以透明地缓存结果,而无需让用例了解具体实现细节。

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) }
}

可测试性

由于用例依赖仓储协议,因此可以注入存根,隔离测试业务逻辑。

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

错误转换

仓储应在返回数据层错误(网络错误、数据库错误)之前,将其转换为领域错误。

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
  }
}

快速检查

在清晰架构中,仓储与服务之间的关键区别是什么?

课程回顾

用例封装单项业务操作,并依赖仓储协议。仓储通过协议对数据源进行抽象。使用内存仓储可以执行快速测试。仓储将基础设施错误转换为领域错误。服务负责协调涉及多个实体的操作。

常见问题解答

「用例与仓储模式」课时是免费的吗?

是的 — 「用例与仓储模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「用例与仓储模式」这节课中我会学到什么?

将用例定义为 Swift 协议,并实现仓储接口。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「用例与仓储模式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 分层:领域、数据与表示层
  2. 用例与仓储模式
  3. 使用协议抽象实现依赖倒置
  4. 不使用 DI 框架组装各层
← 返回 Swift Academy