更好地理解依赖注入 - 解决新实例?
Better understanding of Dependency Injection - Resolving New Instances?
我的工作要求我专注于依赖注入。对于后代,我在 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
}
}
这将在下面变得相关,但我的项目中有一个 class,名为 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
有其自身的依赖性,导致我不确定如何注册类型。
我不确定我的问题是否存在于我的依赖容器的构建方式中,我的 classes 的构建方式中,或者如果我只是不理解被问到的问题.即使查看像 Swinject or DIP 这样流行的 Swift 库,我也没有完全看出我的 Container 做错了什么(或者如果这是工厂方法的用武之地)。
您需要添加一个额外的注册函数。
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是一样的
我的工作要求我专注于依赖注入。对于后代,我在 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
}
}
这将在下面变得相关,但我的项目中有一个 class,名为 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
有其自身的依赖性,导致我不确定如何注册类型。
我不确定我的问题是否存在于我的依赖容器的构建方式中,我的 classes 的构建方式中,或者如果我只是不理解被问到的问题.即使查看像 Swinject or DIP 这样流行的 Swift 库,我也没有完全看出我的 Container 做错了什么(或者如果这是工厂方法的用武之地)。
您需要添加一个额外的注册函数。
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是一样的