2014-10-28 140 views
2

Swift中沒有抽象類。具有共享方法的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] 
} 

回答

2

這裏有一種方法我可以做到這一點:

  1. 聲明一個protocol AnimalType。在它裏面,定義一個動物是什麼,它可以做什麼,但不知道它是如何做的。這個命名約定使用遍佈雨燕標準庫:CollectionTypeSequenceTypeIntegerTypeBooleanType
  2. 聲明一個class Animal定義所有的動物怎麼辦,他們共同擁有的東西;對於其他任何東西,只需製作佔位符函數或屬性(這是您的「抽象」類)。如果你有一個功能對你的抽象類沒有任何意義,請在它的正文中調用fatalError()
  3. 根據需要創建您的具體class Dog,class Bird等和override功能和/或添加新功能。

事情是這樣的:

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> 

嘗試一些東西out:

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() 

fatal error: run() can not be called on the Animal class: file <EXPR>, line 18

+0

擁有'AnimalType'協議有什麼好處? – 2014-10-29 04:27:00

+0

IE,你可以使用'let animals:[動物] = ...',我不認爲你會因此而失去任何東西。 – 2014-10-29 04:38:01

+2

@AaronBrager true,'[動物]'會工作得很好。一般來說,我會說它允許實現相同協議的不同基類。具體而言,在這種情況下,可能沒有太多意義。 – 2014-10-29 04:58:13