Here's one way I might do it:
- Declare a
protocol AnimalType
. In it, define what an animal is and what it can do, but not how it does anything. This naming convention is used all over the Swift standard library: CollectionType
, SequenceType
, IntegerType
, BooleanType
, etc.
- Declare a
class Animal
that defines how all animals do the things that they have in common; for everything else, just make placeholder functions or properties (this is your "abstract" class). If you have a function that doesn't make sense to call on your abstract class, call fatalError()
in it's body.
- Create your specific
class Dog
, class Bird
, etc. and override
functions and/or add new ones as needed.
Something like this:
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())
}
}
Then, if you need say an Array
of animals, declare the array using the protocol, not the Animal
class:
let animals: Array<AnimalType>
Trying some stuff out:
let dog = Dog()
println("Dogs have \(dog.legCount()) legs.")
dog.run()
let bird = Bird()
println("Birds have \(bird.legCount()) legs.")
bird.run()
Which will output:
Dogs have 4 legs.
Running Dog!
Birds have 2 legs.
Running Bird!
The Array
also works:
var animals: Array<AnimalType> = [dog, bird]
var legs = animals.map { $0.legCount() }
println(legs)
[4, 2]
And, while Animal
can still be instantiated:
let a = Animal()
Calling run()
on it will be a fatal error:
a.run()
fatal error: run() can not be called on the Animal class: file <EXPR>, line 18