使用共享方法的swift抽象类

时间:2014-10-28 22:38:22

标签: design-patterns swift abstract-class virtual-functions

Swift中没有抽象类。

人们有其他方法可以拥有类似的机制。但他们不回答我的问题。如何构建具有相同功能和一些不同功能的类系列?

Abstract classes in Swift Language表明我们使用协议而不是抽象基类。但是协议不是我们可以编写函数体的地方,所以对于每个子类中的相同函数,我们必须编写与子类号一样多的时间。

我想要的是这样的:

protocol Animal : class {
    func run()
    var legs : [Leg] { get }

    // this method is invalid in swift protocol
    // as protocol methods must have no bodies.
    // Instead, the same method will be repeated
    // in every subclasses

    func legCount() -> Int {
       return self.legs.count
    }
}

class Dog : Animal {
    func run() {}
    var legs : [Leg]
}

class Bird : Animal {
    func run() {}
    var legs : [Leg]
}

1 个答案:

答案 0 :(得分:2)

这是我可能采取的一种方式:

  1. 声明protocol AnimalType。在其中,定义动物是什么以及它能做什么,而不是它如何做任何事情。此命名约定在整个Swift标准库中使用:CollectionTypeSequenceTypeIntegerTypeBooleanType等。
  2. 宣布class Animal,定义所有动物如何做他们共同的事情;对于其他一切,只需制作占位符函数或属性(这是你的"抽象"类)。如果你有一个对抽象课程打电话没有意义的功能,请打电话给它fatalError()
  3. 根据需要创建您的特定class Dogclass Bird等和override功能和/或添加新功能。
  4. 这样的事情:

    struct Leg { } // Just so it'll run in a Playground
    
    protocol AnimalType: class {
        func run()
        var legs : [Leg] { get }
        func legCount() -> Int
    }
    
    class Animal: AnimalType {
        func run() {
            fatalError("run() can not be called on the Animal class")
        }
    
        var _legs: [Leg]! = nil
        var legs: [Leg] { get { return _legs } }
    
        func legCount() -> Int {
            return legs.count
        }
    }
    
    class Dog: Animal {
        override func run() {
            println("Running Dog!")
        }
    
        override init() {
            super.init()
            _legs = [Leg](count: 4, repeatedValue: Leg())
        }
    }
    
    class Bird : Animal {
        override func run() {
            println("Running Bird!")
        }
    
        override init() {
            super.init()
            _legs = [Leg](count: 2, repeatedValue: Leg())
        }
    }
    

    然后,如果您需要说Array个动物,请使用协议声明数组,而不是Animal类:

    let animals: Array<AnimalType>
    

    尝试一些东西:

    let dog = Dog()
    println("Dogs have \(dog.legCount()) legs.")
    dog.run()
    
    let bird = Bird()
    println("Birds have \(bird.legCount()) legs.")
    bird.run()
    

    将输出:

    Dogs have 4 legs. 
    Running Dog! 
    Birds have 2 legs. 
    Running Bird!
    

    Array也有效:

    var animals: Array<AnimalType> = [dog, bird]
    var legs = animals.map { $0.legCount() }
    println(legs)
    
      

    [4,2]

    而且,Animal仍然可以实例化:

    let a = Animal()
    

    在其上调用run()将是一个致命的错误:

    a.run()
    
      

    致命错误:无法在Animal类上调用run():file&lt; EXPR&gt;,第18行