更好地理解依赖注入-解决新实例?



我一直在工作,需要我专注于依赖注入。为了子孙后代,我在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有它自己的依赖关系,导致我不确定如何注册一个类型。

我不确定我的问题是否存在于我的依赖容器的构建方式,我的类的构建方式,或者如果问题是问我什么,我只是不理解。即使看看流行的Swift库,如Swinject或DIP,我也不能完全看到我的容器做得不正确(或者如果这是工厂方法的来源)。

您需要添加一个额外的寄存器函数。

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

如果你在操场上运行这段代码并解析PersonAnimal几次,你会看到UUID都是不同的,而ComplicatedNetworkStack的id是相同的。

最新更新