作為規範介面的特徵


繼 承的目的之一,在於延用父類別已有的程式碼,並重新定義不適合或增加新的定義,然後有些時候,並不適合用繼承來解決問題,尤其在單一繼承的語言中,例如在 Scala中,一次只能繼承自一個類別,多重繼承在Scala中是不允許的,這使得「是一種」(is a)的關係在繼承時更為加強,例如,你繼承自鳥類,就必然「是一種」鳥。

舉個例子來說,鳥會飛,超人也會飛,但超人不會是一種鳥(如果你硬要說鳥人也是超人,那我投降),如果你只是為了飛行這個行為,讓超人去繼承鳥就不適當。

在Scala中,你可以定義特徵(Trait),類別可以繼承(extends)特徵:
trait Flyer {
def fly(): Unit
}

class Bird extends Flyer {
def fly() = println("使用翅膀")
}

class Superman extends Flyer {
def fly() = println("使用超人披風")
}

def doFly(flyer: Flyer) {
flyer.fly()
}

val bird = new Bird
val man = new Superman
doFly(bird) // 顯示使用翅膀
doFly(man) // 顯示使用超人披風

你使用trait關鍵字來定義特徵,特徵的作用之一,就是規範必須實作的介面,也就是特徵中僅定義無任何實作程式碼的抽象方法,如果定義的是無實作的抽象方法,則繼承特徵的類別必須實作(如同Java的interface)。

若類別本身沒有繼承自別的父類別,則可以直接繼承特徵,也就是直接使用extends關鍵字。上例中,iamFly()函式可接受具Flyer特徵的物件進行多型操作。

類別亦可繼承自某個父類別,並具有(with)指定的特徵,例如:
trait Flyer {
def fly(): Unit
}

class Animal

class Bird extends Animal with Flyer {
def fly() = println("使用翅膀")
}

val bird = new Bird
bird.fly() // 顯示使用翅膀

一個類別可以具有多個特徵,例如:
trait Flyer {
def fly(): Unit
}

trait Sailer {
def cruise(): Unit
}

class Vehicle

class SeaPlane extends Vehicle with Flyer with Sailer {
def fly() = println("使用螺旋槳")
def cruise() = println("航行")
}

特徵可以繼承自另一個特徵,例如:
trait Sailer {
def cruise(): Unit
}

trait Diver extends Sailer {
def dive(): Unit
}

class Submarine extends Diver {
def cruise() = println("航行")
def dive() = println("潛水")
}

如果要繼承多個特徵,則特徵之間亦使用with結合,例如:
trait A
trait B
trait C extends A with B