【译】Swift 中使用工厂方法的依赖注入
· 8 min read
阅读原文,作者是John Sundell
依赖注入的好处暂且不表,大家都知道。最普遍的做法是在初始化的时候传入它所需要的所有依赖,但是碰到下面 这种情况,你就会感觉很蛋疼了:
class UserManager {
init(dataLoader: DataLoader, database: Database, cache: Cache,
keychain: Keychain, tokenManager: TokenManager) {
...
}
}
这就导致了一个Massive的初始化器,以及复杂的依赖管理问题。
传递依赖
在使用依赖注入时,我们经常陷入上面这种情况,原因是为了以后可能要用到它,那我们就必须传递下去。
举个例子,我们有个MessageListViewController
消息类,它依赖MessageLoader
,用来加载所有消息:
class MessageListViewController: UITableViewController {
private let loader: MessageLoader
init(loader: MessageLoader) {
self.loader = loader
super.init(nibName: nil, bundle: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loader.load { [weak self] messages in
self?.reloadTableView(with: messages)
}
}
}
目前看来问题不大,因为我们只有一个依赖。然而,假设我们需要在点击列表项时,导航到下一个视图MessageViewController
,让用户查看消息详情,并且回复消息。为了实现这个功能,我们需要一个MessageSender
消息发送类,注入到MessageViewController
,就像这样:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let message = messages[indexPath.row]
let viewController = MessageViewController(message: message, sender: sender)
navigationController?.pushViewController(viewController, animated: true)
}
问题来了,因为MessageViewController
需要一个MessageSender
的实例,所以我们得让MessageListViewController
知晓有这么一个类。最简单的方法就是,在MessageListViewController
初始化的时候,也添加一个sender
:
class MessageListViewController: UITableViewController {
init(loader: MessageLoader, sender: MessageSender) {
...
}
}
虽然上面的代码可以工作,但是它让我们走入了Massive
初始化器的道路上,使MessageListViewController
更难用了(好奇的是,为什么列表一开始就要关心sender
?)。
另外一个普遍的方法就是使用单例,到处都可以访问,而且很方便:
let viewController = MessageViewController(
message: message,
sender: MessageSender.shared
)
但是,我们必须避免使用单例。单例方法伴随着很多重大的缺点,会让我们很难理解不清楚的依赖架构。