Swift - 混合抽象和具体方法

Swift - mixing abstract and concrete methods

Swift 没有抽象的 classes 和方法。相反,它提供协议。

当您的 class 完全抽象或完全具体时,这很好。

但是什么是最好的 'Swift' 实现抽象 class 也有具体方法的方法?

伪代码示例:

class Animal {
  abstract makeSound()
  abstract eyeCount()
}

class Mammal : Animal {
  override eyeCount { return 2 } // Let's assume all mammals have hard-coded 2 eyes...

class Cat : Mammal {
  override makeSound { print "Meow!" }
}

class Dog : Mammal {
  override makeSound { print "Woof!" }
}

在哺乳动物中,我确实想实现具体方法 eyeCount(),因为所有哺乳动物都有 2 只硬编码的眼睛(据说),我不想在狗和猫中重新实现它。但是,makeSound() 应该只对狗和猫实施,因为哺乳动物有不同的声音。

您将如何在 Swift 中实现它?谢谢!

执行此操作的常用方法是创建一个包含具体方法的抽象 class。所有 classes 都可以子class 这个抽象 class 来继承具体方法和抽象方法。

UIGuestureRecognizerUIGuestureRecognizerSubclass 就是一个很好的例子。因为这是为 subclassing 而设计的,所以这个抽象 class 包含许多内部具体方法以及 subclassable 抽象方法供您实现。

这是许多 Swift 和 Objective-C 项目的常见模式。

正如@BobDickinson 在 Abstract functions in Swift Language 中所建议的那样,您可以这样做的一种方法如下:

protocol Animal {
    var eyeCount: Int { get }
    func makeSound()
}

// Note - `Mammal` doesn't conform to `Animal`.
class Mammal {
    let eyeCount = 2
}

// Only `Cat` and `Dog` conform to `Animal`, so only they need to implement `makeSound`.
class Dog: Mammal, Animal {
    func makeSound() {
        println("Woof")
    }
}

class Cat: Mammal, Animal {
    func makeSound() {
        println("Meow")
    }
}

我会这样实现:

class AbstractAnimal
{
    // Fully abstract method
    func methodThatReturnsSomething() -> String  {
        fatalError("methodThatReturnsSomething() is abstract and must be overriden!");
    }

    func eyeCount() -> Int {
        return 2;
    }
}

fatalError 阻止 Xcode 抱怨抽象方法 methodThatReturnsSomething() 实际上 return 什么都没有。

您可以使用 Protocol Extensions 获得与 Abstract 类 完全相同的行为:检查抽象方法是否是在编译时在子类中实现。

protocol Entity {
  // MARK: - Abstract methods
  func filename() -> String

  // MARK: - Traits
  func saveData(data: NSArray)
}

extension Entity {
  func saveData(data: NSArray) {
      // Do something and call:
      let filename = filename()
  }
}

现在您可以在 子类 上实现 Entity 协议,编译器将强制您实现 filename()saveData() 方法已经实施了。