我不明白为什么需要通过全局状态访问 userModel 或 someManager(是的,单例就是这样)。
为什么不把它放在你需要的地方呢?
“依赖注入”是 5 美分概念的 25 美元术语。
这并不是说这是一个坏词……
[…]
依赖注入手段
给一个对象它的实例变量。真的。就是这样。
– 詹姆斯·肖尔:Dependency Injection Demystified
在构建过程中进行
class C {
let currentUser: UserModel
let someManager: SomeManager
init(currentUser:UserModel, someManger:SomeManager) {
self.currentUser = currentUser
self.someManager = someManager
}
}
或通过属性。如果您需要确保设置了所有属性,请执行以下操作:
class MyController: UIViewController {
var currentUser: UserModel? {
didSet{
self.configureIfPossible()
}
}
var someManager: SomeManager?{
didSet{
self.configureIfPossible()
}
}
func configureIfPossible(){
if let currentUser = self.currentUser, someManager = self.someManager {
// configure
}
}
}
在我当前的项目中,我们的政策是每个依赖项都必须从类外部可见和可配置。
一个例子:
class LibrarySegmentViewController: BaseContentViewController {
var userDefaults: NSUserDefaults?
var previousSorting : LibrarySortingOrder = .AZ
var sorting : LibrarySortingOrder {
set{
self.previousSorting = sorting
if let filterMode = self.filterMode {
self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting")
}
self.setupIfReady()
}
get{
if let filterMode = self.filterMode {
if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) {
return s
}
}
return .Date
}
}
}
如您所见,我们甚至使用属性来引用NSUserDefaults.standardUserDefaults()。我们这样做是因为我们可以在测试期间传递新的实例,而不会带来更大的嘲笑麻烦。
这是为什么不直接使用单例的最重要的原因:依赖项是隐藏的,可能会在测试和重构期间咬你。另一个示例是隐藏在代码中并在测试期间执行不需要的网络请求的 API 客户端单例。如果它是从测试类外部设置的,您可以传入一个不执行任何请求但返回测试数据的模拟网络客户端。
因此,即使您使用单例,您也应该将其作为依赖项传递。