第 13 课2026.07.29
构造器注入解决了“类如何接收依赖”,但仍需要一个地方创建真实的 Ktor Client、数据源、Repository 和用例。这个集中组装对象图的位置通常称为 Composition Root(组合根)。
第 13 课:手动组装共享依赖
- 日期:2026-07-29
- 课程序号:13
- 知识点:在 Composition Root 中集中创建并连接共享对象
用途
构造器注入解决了“类如何接收依赖”,但仍需要一个地方创建真实的 Ktor Client、数据源、Repository 和用例。这个集中组装对象图的位置通常称为 Composition Root(组合根)。
核心概念
- 对象只声明自己需要什么,组合根负责决定使用哪个具体实现。
- Ktor Client、Repository 等长生命周期对象应集中创建并复用。
- 页面接收已经组装好的用例或 Repository,不在页面里重复创建整条依赖链。
- 需要释放的共享资源由拥有组合根的平台入口统一关闭。
- 小型项目先用普通 Kotlin 类手动组装即可,不必立即引入 DI 框架。
示例代码
假设前几课已经实现了 KtorUserApi、DefaultUserRepository、GetUserLabel 和 createHttpClient()。
在 commonMain 中集中组装它们:
kotlin
import io.ktor.client.HttpClient
class AppContainer(
private val httpClient: HttpClient,
) {
private val userApi: UserApi = KtorUserApi(httpClient)
val userRepository: UserRepository =
DefaultUserRepository(userApi)
val getUserLabel: GetUserLabel =
GetUserLabel(userRepository)
fun close() {
httpClient.close()
}
}
fun createAppContainer(): AppContainer {
return AppContainer(
httpClient = createHttpClient(),
)
}平台应用入口只创建一次容器,再把需要的依赖传给页面:
kotlin
val appContainer = createAppContainer()
// 页面或状态持有者接收已经组装好的用例
val getUserLabel = appContainer.getUserLabel应用生命周期结束时,由持有容器的平台入口调用:
kotlin
appContainer.close()这样对象的创建位置、复用范围和释放责任都清晰可见。
5 分钟练习
假设已经有 GetUser 用例,请把它加入 AppContainer,并复用现有的 userRepository。
参考答案
kotlin
class AppContainer(
private val httpClient: HttpClient,
) {
private val userApi: UserApi = KtorUserApi(httpClient)
val userRepository: UserRepository =
DefaultUserRepository(userApi)
val getUserLabel: GetUserLabel =
GetUserLabel(userRepository)
val getUser: GetUser =
GetUser(userRepository)
fun close() {
httpClient.close()
}
}两个用例共享同一个 Repository,Repository 也共享同一个 HttpClient,不会因页面重建而重复创建网络客户端。
与上一课的联系
上一课介绍了通过构造器传入依赖;本课补齐对象图的另一半:在应用入口集中创建真实实现并连接它们。后续页面只消费组装结果,不承担数据层对象的创建责任。