如何解决更好地理解依赖注入 - 解析新实例?
我的工作要求我专注于依赖注入。对于后代,我在 Swift/SwiftUI 中使用它,尽管我相信我对概念的缺乏理解比语言更固有。
我创建了一个依赖注入容器,可以用来注册和解析类型和组件。因此;
protocol MyContainerProtocol {
func register<Component>(type: Component.Type,component: Any)
func resolve<Component>(type: Component.Type) -> Component?
}
final class MyContainer: MyContainerProtocol {
static let shared = DependencyContainer()
private init() { }
var components: [String: Any] = [:]
func register<Component>(type: Component.Type,component: Any) {
components["\(type)"] = component
}
func resolve<Component>(type: Component.Type) -> Component? {
return components["\(type)"] as? Component
}
}
这将在下面变得相关,但我的项目中有一个类,名为 VideoProcessor
;
class VideoProcessor: SomeProtocol {
var codec: String
var format: String
init(codec: String,format: String) {
self.codec = codec
self.format = format
}
}
在应用程序生命周期的早期,我正在注册组件。例如;
let container = DependencyContainer.shared
container.register(type: VideoProcessor.self,component: VideoProcessor(codec: "H264",format: "MP4"))
...
let processor = container.resolve(type: VideoProcessor.self)!
我的困惑: 要求我解析一个类型的实例,而不必在注册时构造它。实际上,每次解析时,我都被要求解析已注册类型的新实例。在我看来,这意味着我的代码类似于;
let container = DependencyContainer.shared
container.register(type: VideoProcessor.self)
...
let processorA = container.resolve(type: VideoProcessor.self)!
processorA.codec = "H264"
processorA.format = "MP4"
let processorB = container.resolve(type: VideoProcessor.self)!
processorB.codec = "H265"
processorB.format = "MOV"
但是,VideoProcessor
有自己的依赖项,这让我不确定如何注册类型。
我不确定我的问题是否存在于我的依赖容器的构建方式、我的类的构建方式,或者我只是不理解被问到的问题。即使查看像 Swinject 或 DIP 这样的流行 Swift 库,我也不能完全看出我的 Container 做错了什么(或者这是否是 Factory 方法的用武之地)。
解决方法
您需要添加一个额外的寄存器功能。
protocol MyContainerProtocol {
func register<Component>(type: Component.Type,component: Any)
func register<Component>(type: Component.Type,builder: @escaping (MyContainerProtocol) -> Component)
func resolve<Component>(type: Component.Type) -> Component?
}
final class MyContainer: MyContainerProtocol {
static let shared = MyContainer()
private init() { }
var components: [String: Any] = [:]
func register<Component>(type: Component.Type,component: Any) {
components["\(type)"] = component
}
func register<Component>(type: Component.Type,builder: @escaping (MyContainerProtocol) -> Component) {
components["\(type)"] = builder
}
func resolve<Component>(type: Component.Type) -> Component? {
if let singleton = components["\(type)"] as? Component {
return singleton
}
if let builder = components["\(type)"] as? (MyContainerProtocol) -> Component {
return builder(self)
}
return nil
}
}
然后它在呼叫站点看起来像这样:
struct Animal {
let type: String
let id = UUID()
}
struct Person {
let name: String
let pet: Animal
let id = UUID()
}
class ComplicatedNetworkStack {
let id = UUID()
/// so much stuff in here
}
MyContainer.shared.register(type: Animal.self) { _ in Animal(type: "Dog") }
MyContainer.shared.register(type: Person.self) { container in
Person(
name: "Joe Dirt",pet: container.resolve(type: Animal.self)!
)
}
MyContainer.shared.register(type: ComplicatedNetworkStack.self,component: ComplicatedNetworkStack())
如果您在 Playground 中运行该代码并解析 Person
和 Animal
几次,您会看到 UUID 全都不同,而 ComplicatedNetworkStack
的 id 是一样。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。