了解如何将 类 变成 Swift 中的协议

Understanding how to turn Classes into Protocols in Swift

我的代码工作正常!但是,我对抽象 classes 和协议研究得越多,我就越开始认为我代码背后的 "logic" 是完全错误的。让我更详细地解释一下:

我有一个名为 SpaceObjectclass,它是对继承的 classes 的一种抽象。它基本上具有一些属性和物理特性。 不应初始化此 class,因为它的工作方式与 "blueprint"

相同
class SpaceObject: SKSpriteNode {

    final var atmosphere: SKSpriteNode

    init(style: SKTexture, initialVelocity: CGVector) {
        atmosphere = SKSpriteNode(texture: SKTexture(imageNamed: "atmosphere"), size: CGSize(width: 100, height: 100))
        atmosphere.zPosition = 2

        // calls the initializer
        super.init(texture: style, color: .clear, size: style.size())

        physicsBody = SKPhysicsBody(circleOfRadius: style.size().width)
        physicsBody?.velocity = initialVelocity
        physicsBody?.affectedByGravity = false
        ...

        addChild(atmosphere)
    }

    final func cleanAtmosphere() {
        atmosphere.run( ... )
    }

}

我这里有子classes。他们只是 "fill" SpaceObject class 但使用它的物理学和一些其他功能(例如 cleanAtmosphere())。

final class World: SpaceObject {

    enum WorldType: String {
         case Venus, Earth, ...
    }

    var type: WorldType
    var gravity: CGFloat

    init(world: WorldType, initialVelocity: CGVector, gravity: CGFloat) {
        self.type = world
        self.gravity = gravity

        // calls the initializer
        super.init(style: SKTexture(imageNamed: "world_\(self.type)"), initialVelocity: initialVelocity)
    }

    func touchedOccurred() {
        ...
        cleanAtmosphere()
        ...
    }

}
final class Star: SpaceObject {

    enum StarType: String {
         case Sirius, Polaris, ...
    }

    var type: StarType

    init(star: StarType, initialVelocity: CGVector) {
        self.type = star

        // calls the initializer
        super.init(style: SKTexture(imageNamed: "star_\(self.type)"), initialVelocity: initialVelocity)
    }

    func explode() {
        ...
    }

}

我创建一个对象只是:

let newWorld = World(world: .Venus, initialVelocity: someVector, gravity: CGFloat(8.87))

而且我确定它会有大气层 SKSpriteNode 和一些对每个 SpaceObject 都有效的物理规则。

但是...我不确定我做的是否正确,我读到协议需要处理这样的情况,但我仍然不知道如何处理。有什么提示吗?

您可以使用继承来做您想做的事,但协议也是一种选择。协议的优点是 Swift 结构可以使用它们并且 class 可以符合多个协议但只能继承一个 class.

你提到了物理规则。如果你想使用一个协议,你可以为规则创建一个协议,并包含 classes/structs 必须实现以符合该协议的功能。该函数将创建规则。

protocol PhysicsRules {
    // Add any arguments the function takes.    
    func yourPhysicsRule()

    // Add any other physics functions you want here.
}

那你的World和Starclasses就符合协议,实现了yourPhysicsRule功能

final class World: SpaceObject, PhysicsRules {

   func yourPhysicsRule() {
        // Add the code to create the rule here.
    }

}

您可以为协议和函数想出更好的名称,但这让您了解了要转换到协议必须执行的操作。

通过网络搜索 Swift protocols 可以找到很多面向协议编程的教程,包括以下内容:

A Beginner’s Guide to Protocols and Protocol Extensions in Swift

Protocol-Oriented Programming Tutorial in Swift 5.1: Getting Started