最近我遇到了面向协议的编程(WWDC 2015),它真的很吸引人,但它是一个很难被驯服并将其付诸实践的概念。所以我在互联网上做了一些研究并发现了这段代码。它在典型的游戏场景中模拟玩家和敌人,玩家可以装备武器并射击敌人,然后敌人会受到伤害:
protocol Targetable {
var life: Int { get set }
func takeDamage(damage: Int)
}
protocol Shootable {
func shoot(target: Targetable)
}
class Pistol: Shootable {
func shoot(target: Targetable) {
target.takeDamage(1)
}
}
class Shotgun: Shootable {
func shoot(target: Targetable) {
target.takeDamage(5)
}
}
class Enemy: Targetable {
var life: Int = 10
func takeDamage(damage: Int) {
life -= damage
println("enemy lost \(damage) hit points")
if life <= 0 {
println("enemy is dead now")
}
}
}
class Player {
var weapon: Shootable!
init(weapon: Shootable) {
self.weapon = weapon
}
func shoot(target: Targetable) {
weapon.shoot(target)
}
}
var terminator = Player(weapon: Pistol())
var enemy = Enemy()
terminator.shoot(enemy)
//> enemy lost 1 hit points
对我来说,这很有道理。但是,在我的脑海里,我告诉自己“是的,这是有道理的,但如果我要实现这样的东西,它将完全不同”,所以我做了:
class Gun {
var damage: Int {
return 0
}
}
class Pistol: Gun {
override var damage: Int {
return 5
}
}
class Shotgun: Gun {
override var damage: Int {
return 10
}
}
class Enemy {
var health = 100
func takeDamage(damage: Int) {
health = health - damage
print("Current health is: \(health)")
}
init(health: Int) {
self.health = health
}
}
class Player {
var gun: Gun
func shoot(enemy: Enemy) {
enemy.takeDamage(damage: gun.damage)
}
init(gun: Gun) {
self.gun = gun
}
}
let player = Player(gun: Pistol())
let enemy = Enemy(health: 100)
player.shoot(enemy: enemy)
//Current health is: 95
他们两个模型共享相同的损害机制,你有一种方法是协议和对象的混合,另一方面你有纯粹的对象。很多人可以告诉我哪种方法最好,为什么?
谢谢!
答案 0 :(得分:2)
哪个更好是一个主观问题,据我所知,本网站不鼓励这个问题。然而,第一个更符合面向协议的#34;最近由Swift社区推荐的成语。
然而,关于你的第二个例子,有一点是你的Gun
超类除了定义一个接口之外没什么作用;它自己的damage
实现从未实际使用过。因此,在这种情况下,协议肯定是正确的方法。
答案 1 :(得分:0)
POP的一个优点是类/结构可以采用多个协议,而类可以只是一个超类的子类。在上面的示例中,如果您想要玩家也可以(由敌人或其他玩家)进行射击,您只需要使Player类符合Targetable协议
class Player: Targetable { ... }
其次,一旦使用Protocol作为Type,该Type的变量可以是符合本协议的任何Class的实例。 在上面和现实世界的例子中,玩家的武器可以是霰弹枪或手枪,并且可以随时更改。
var terminator = Player(life: 100, weapon: Pistol())
var enemy = Enemy()
terminator.shoot(enemy)
//> enemy lost 1 hit points
terminator.weapon = Shotgun()
terminator.shoot(enemy)
//> enemy lost 5 hit points
它们只是展示POP优势的几点,在更具体的案例中应该有更多。