依赖注入是一种很好的解耦代码并使其更容易测试的技术。您不必让对象自己创建自己的依赖项,而是从外部注入它们,使您能够针对各种情况进行不同的设置。
大多数时候,我们使用协议在Swift中启用依赖注入。虽然当我们的API更复杂时基于协议的依赖注入很好,但当它只有一个目的(并且只需要一个方法)时,我们可以通过简单地使用函数来降低我们的复杂性。
例如我们编写一个简单的英雄选择逻辑,我用使用randomizer从英雄池中随机的抽取英雄如下所示,最开始我们可能会这样写:
struct Hero {
var name: String = "name"
//...
}
class LOLGame {
private let heros: [Hero]
init(heros: [Hero]) {
self.heros = heros
}
func randomHero() -> Hero {
let index = Int(arc4random_uniform(UInt32(heros.count)))
return heros[index]
}
}
class AViewController: UIViewController {
func chooseHero() -> Hero {
let manager = LOLGame(heros: [Hero(name: "剑圣"), Hero(name: "皇子"), Hero(name: "德玛")])
return manager.randomHero()
}
}
如果我每次玩游戏时要更换选英雄的规则,怎么办呢?我们通常会再给LOLGame
加上类似hero(at index:index) -> Hero
方法。但是如果我们能从外部注入依赖,情况看上去就会好得多,经过调整,代码如下
struct Hero {
var name: String = "name"
//...
}
class LOLGame {
typealias Randomizer = (UInt32) -> UInt32
private let heros: [Hero]
private let randomizer: Randomizer
init(heros: [Hero], randomizer: @escaping Randomizer = arc4random_uniform ) {
self.heros = heros
self.randomizer = randomizer
}
func selectedHero() -> Hero {
let index = Int(randomizer(UInt32(heros.count)))
return heros[index]
}
}
class AViewController: UIViewController {
func chooseHero() -> Hero {
let manager = LOLGame(heros: [Hero(name: "剑圣"), Hero(name: "皇子"), Hero(name: "德玛")])
return manager.selectedHero()
}
func allowChooseJS() -> Hero {
let manager = LOLGame(heros: [Hero(name: "剑圣"), Hero(name: "皇子"), Hero(name: "德玛")]) {_ in
return 0
}
return manager.selectedHero()
}
func chooseHero(at index: UInt32) -> Hero {
let manager = LOLGame(heros: [Hero(name: "剑圣"), Hero(name: "皇子"), Hero(name: "德玛")]) {_ in
return index
}
return manager.selectedHero()
}
}
这样改动后,可以在不动LOLGame
的情况下,扩展功能。
这种定义API的好处在于"设计支持变化",如果API更复杂,还是通过协议启用依赖注入比较好,具体视情况而定,这里只是提供编程的一种思路。
如果您有任何问题,建议或反馈,请随时与我联系~
网友评论