面向协议编程与面向对象编程的不同之处

时间:2017-08-31 20:25:48

标签: swift protocols

最近我遇到了面向协议的编程(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

他们两个模型共享相同的损害机制,你有一种方法是协议和对象的混合,另一方面你有纯粹的对象。很多人可以告诉我哪种方法最好,为什么?

谢谢!

2 个答案:

答案 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优势的几点,在更具体的案例中应该有更多。