Resolver: Injection Strategies

2021-02-03  本文已影响0人  怪客半

Resolver: Injection Strategies翻译

注入策略

使用 Resolver 执行依赖项注入的主要方法有五种:

  1. 接口注入
  2. 属性注入
  3. 构造器注入
  4. 方法注入
  5. 服务定位器
  6. 注释 (NEW)

名称和数量都来自于依赖反转,有关更深入的讨论,请参考 Martin Fowler.

Here I'll simply provide a brief description and an example of implementing each using Resolver.
在这里,我将简单地描述下每种策略,并提供 Resolver 实现对应策略的例子。

1. 接口注入

定义

第一种注入技术是为注入定义一个接口,并使用Swift扩展将该接口注入到类或对象中。

类:
class XYZViewModel {

    lazy var fetcher: XYZFetching = getFetcher()
    lazy var service: XYZService = getService()

    func load() -> Data {
        return fetcher.getData(service)
    }

}
依赖注入的代码:
extension XYZViewModel: Resolving {
    func getFetcher() -> XYZFetching { return resolver.resolve() }
    func getService() -> XYZService { return resolver.resolve() }
}

func setupMyRegistrations {
    register { XYZFetcher() as XYZFetching }
    register { XYZService() }
}

请注意,仍需要在getFetcher() 和getService() 中调用resolve(),否则您将返回到紧密耦合依赖类并绕过解析注册系统。

优点:
缺点:

2. 属性注入

定义

属性注入将其依赖项公开为属性,依赖项注入系统需要确保在调用任何方法之前都已设置好。

类:
class XYZViewModel {

    var fetcher: XYZFetching!
    var service: XYZService!

    func load() -> Data {
        return fetcher.getData(service)
    }

}
依赖注入代码
func setupMyRegistrations {
    register { XYZViewModel() }
        .resolveProperties { (resolver, model) in
            model.fetcher = resolver.optional() // Note property is an ImplicitlyUnwrappedOptional
            model.service = resolver.optional() // Ditto
        }
}


func setupMyRegistrations {
    register { XYZFetcher() as XYZFetching }
    register { XYZService() }
}
优点:
缺点:

3.构造器注入

定义

构造函数是Swift初始值设定项的Java术语,但其思想是相同的:通过初始化函数传递对象所需的所有依赖项。

类:
class XYZViewModel {

    private var fetcher: XYZFetching
    private var service: XYZService

    init(fetcher: XYZFetching, service: XYZService) {
        self.fetcher = fetcher
        self.service = service
    }

    func load() -> Image {
        let data = fetcher.getData(token)
        return service.decompress(data)
   }

}
依赖注入代码
func setupMyRegistrations {
    register { XYZViewModel(fetcher: resolve(), service: resolve()) }
    register { XYZFetcher() as XYZFetching }
    register { XYZService() }
}
优点:
缺点:

4.方法注入

定义

它不是一个模式,而是直接使用解析器,罗列出来以供选择。
就像它的名字一样,是将所需的对象注入到给定的方法中。

类:
class XYZViewModel {

    func load(fetcher: XYZFetching, service: XYZFetching) -> Data {
        return fetcher.getData(service)
    }

}
依赖注入代码

你已经看过了。在load函数中,服务对象被传递到fetcher的getData方法中。

优点:
缺点:
注意

在Swift中,将闭包传递到方法中也可以被视为方法注入的一种形式。

5.服务定位器

定义

服务定位器基本上是定位对象所需的资源和依赖项的服务。

从技术上讲,服务定位器是它自己的设计模式,不同于依赖注入,但是解析器同时支持这两种模式,并且当支持视图控制器和初始化过程不在您控制范围内的其他类时,服务定位器模式特别有用。(请参考故事板。)

类:
class XYZViewModel {

    var fetcher: XYZFetching = Resolver.resolve()
    var service: XYZService = Resolver.resolve()

    func load() -> Data {
        return fetcher.getData(service)
    }

}
依赖注入代码:
func setupMyRegistrations {
    register { XYZFetcher() as XYZFetching }
    register { XYZService() }
}
优点:
缺点:

6.注释

定义

Annotation uses comments or other metadata to indication that dependency injection is required. As of Swift 5.1, we can now perform annotation using Property Wrappers. (See Annotation.)
Annotation使用注释或其他元数据来指示需要进行依赖项注入。从swift5.1开始,我们现在可以使用属性包装器执行注释。(请参考注释。)

类:
class XYZViewModel {

    @Injected var fetcher: XYZFetching
    @Injected var service: XYZService

    func load() -> Data {
        return fetcher.getData(service)
    }

}
依赖注入代码:
func setupMyRegistrations {
    register { XYZFetcher() as XYZFetching }
    register { XYZService() }
}
优点:
缺点:

额外资源

这只是表面现象。要更深入地了解利弊,请参阅: Inversion of Control Containers and the Dependency Injection pattern ~ Martin Fowler

上一篇下一篇

猜你喜欢

热点阅读