2017-08-31 119 views
0

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

嘿,Crusty,再看那个视频。他们并不是说你不能在OOP中提出表示(特别是对于你在这里所拥有的简单的东西),但他们正在展示POP方法的优点。有很多原因可能会导致POP。也许价值语义。或者想象你有“猎人”(有“武器”)和另一个“猎杀”(有“健康”)。那么如果你介绍一个既是“猎人”又是“追捕”的新课程呢?你打算如何表现? POP中的平凡和自然,但在面向对象中卷积。 – Rob

+0

POP是OOP的一部分。使用Swift的事情是协议(接口)不仅可以通过类来实现,还可以通过结构和枚举来实现。您将使用哪种方法还取决于特定情况。 –

+0

我强烈建议你观看[this](https://www.youtube.com/watch?v=AySlYrel7fc)视频。对我来说,WWDC很难实现,用例可能不是那么多...... – Honey

回答

2

哪个更好是主观问题,据我所知在本网站上不鼓励。然而,第一个更符合Swift社区最近推荐的“协议导向”成语。

然而,关于你的第二个例子的一件事是你的Gun超类除了定义一个接口之外没有什么其他的功能;它自己的实现damage从来没有实际使用过。因此,在这种情况下,协议当然似乎是正确的方法。

0

POP的优点之一是类/结构可以采用多个协议,而类只能是一个超类的子类。如果您想要一个球员,也可以shooted(敌人或者其他玩家),你只需要做出Player类,以符合可指定协议

class Player: Targetable { ... } 

其次,一旦你使用一个协议如上面的例子类型,该类型的变量可以是任何符合本协议的类的实例。 在上面的例子和现实世界中,玩家的武器可以是猎枪或手枪,并且可以在任何时候改变。

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的优点,应该有更多的具体情况。