0Pricing
Swift Academy · 课时

使用协议抽象实现依赖倒置

以 Swift 协议作为边界,依赖抽象而非具体实现。

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

依赖倒置原则

高层模块不应依赖低层模块。两者都应依赖抽象(协议)。

// WITHOUT DIP:
class OrderService { let db = SQLiteDatabase() }  // depends on concrete
// WITH DIP:
class OrderService { let db: Database }  // depends on abstraction

定义抽象

提取一个协议,用于描述高层模块所需的契约。

protocol Database {
  func save<T: Encodable>(_ value: T, key: String) throws
  func load<T: Decodable>(key: String) throws -> T
}

具体实现

在协议背后提供多个具体实现:生产实现、测试实现以及未来的替代实现。

class SQLiteDatabase: Database { ... }
class InMemoryDatabase: Database { ... }
class KeychainDatabase: Database { ... }

构造器注入

通过初始化器传入抽象,这是最明确且最易测试的注入方式。

class ProfileService {
  private let db: Database
  init(db: Database) { self.db = db }
}

为什么不把所有内容都做成单例

全局单例会隐藏依赖,使代码难以测试和理解。

// Hard to test:
class Service { func run() { MySingleton.shared.doWork() } }
// Easy to test:
class Service { let dep: MyProtocol; func run() { dep.doWork() } }

Swift 中的协议抽象

Swift 协议可以携带关联类型、默认实现和组合能力,非常适合构建丰富的抽象。

protocol Cacheable {
  associatedtype Key: Hashable
  associatedtype Value
  func get(_ key: Key) -> Value?
  func set(_ key: Key, value: Value)
}

抽象粒度

接口隔离:相比臃肿的协议,应优先使用精简协议,使实现只需提供调用方所需的内容。

// Fat (avoid):
protocol DataStore {
  func save(...); func load(...); func delete(...); func query(...); func migrate()
}
// Narrow (prefer):
protocol Readable { func load<T>(...) throws -> T }
protocol Writable { func save<T>(...) throws }

使用 Combine 实现依赖倒置

让协议方法返回 AnyPublisher,从而隐藏底层发布者类型。

protocol UserStream {
  func userUpdates() -> AnyPublisher<User, Never>
}

使用 async/await 实现依赖倒置

标记为 async throws 的协议方法与 Swift 结构化并发完全兼容。

protocol Analytics {
  func track(event: String) async
}
struct FirebaseAnalytics: Analytics {
  func track(event: String) async { /* Firebase call */ }
}

应用层的依赖倒置

在应用入口(组合根)装配具体实现,将所有绑定集中在一个位置。

@main
struct MyApp: App {
  let db: Database = SQLiteDatabase()
  let repo: UserRepository = RemoteUserRepository(db: db)
  let useCase = FetchUserUseCase(repo: repo)
  var body: some Scene {
    WindowGroup { ContentView(useCase: useCase) }
  }
}

使用依赖倒置进行测试

在测试中,在注入位置用模拟对象或存根替代真实实现。

let mockDB = InMemoryDatabase()
let service = ProfileService(db: mockDB)
// Exercise service
XCTAssertEqual(try mockDB.load(key: "profile"), expectedProfile)

快速检查

依赖倒置原则对高层模块有何规定?

课程回顾

依赖倒置原则:高层模块依赖协议抽象,具体类型实现这些抽象。提取精简协议,通过构造器注入依赖,并在组合根中完成所有装配。这样可以为测试、功能开关和未来需求替换实现。

常见问题解答

「使用协议抽象实现依赖倒置」课时是免费的吗?

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

「使用协议抽象实现依赖倒置」这节课中我会学到什么?

以 Swift 协议作为边界,依赖抽象而非具体实现。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

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

「使用协议抽象实现依赖倒置」课时需要多长时间?

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

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

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

此课程中的所有课时

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