當(dāng)你開始使用繼承來重用代碼時怜瞒,你入門了糟需;當(dāng)你開始避免使用繼承來重用代碼時忘晤,你成熟了
這是我以前在知乎上看到關(guān)于類繼承作用的回答,雖不完全正確齿桃,卻十分明確的表達(dá)出了好的代碼應(yīng)避免類繼承而盡量使用類組合惑惶。Scala 顯然也非常贊同這一點,以至于有了 trait短纵,又叫做特質(zhì)带污。當(dāng)我們定義特質(zhì)時,應(yīng)該要遵循這樣的原則:一個 trait 只干一件事香到,如果要干多件事鱼冀,就定義多個 trait,然后使用一個類來 extends 這些 traits
定義 trait
trait 的定義與 class 類似:
scala> trait T {
| }
defined trait T
當(dāng)然悠就,trait 可以包含成員和方法千绪,并且:
- trait 中的成員可以僅聲明,也可以聲明并指定值
- trait 中的方法可以有實現(xiàn)梗脾,也可以只有聲明而沒有實現(xiàn)
scala> trait T {
| val a: Int
| val b: Int = 1
|
| def getA(): Int
| def getB() = b
| }
defined trait T
對比而言荸型,類一旦包含未定義的方法就必須聲明為 abstract;而 Java 的接口中的方法是不能實現(xiàn)的炸茧,必須是抽象方法帆疟。如果 trait 既為實現(xiàn)它所聲明的方法,也沒有定義或聲明其他成員宇立,那么在字節(jié)碼級別,該 trait 其實是接口是相同的
另一個與類不同的是自赔,trait 主構(gòu)造函數(shù)不允許有參數(shù)列表妈嘹,并且不允許為 trait 定義輔助構(gòu)造函數(shù)
混入多個 trait
Scala 類只能有一個父類,但可以混入多個 trait绍妨,當(dāng)要混入多個 traits 或已經(jīng)繼承了某個父類時润脸,需要使用關(guān)鍵字 with
柬脸,如下例:
scala> trait T {
| val a: Int
| val b: Int = 1
|
| def getA(): Int
| def getB() = b
| }
defined trait T
scala>
scala> trait Q {
| def currentTime: String = System.currentTimeMillis().toString
| }
defined trait Q
scala>
scala> class X extends T with Q {
| override val a = 1
| override def getA(): Int = a
| }
defined class X
當(dāng)類混入 trait 時,需要實現(xiàn) trait 中為實現(xiàn)的成員和方法毙驯。要混入多個 trait 是為了保證『高內(nèi)聚』倒堕,通俗說就是一個 trait 只干一件事,如果要干多件事爆价,就定義多個 trait 然后混入它們
當(dāng)你繼承的父類和混入的特質(zhì)或混入的不同特質(zhì)之間有同名方法時可能會有沖突垦巴,分為以下幾種情況:
- trait 中的方法未實現(xiàn):不會沖突
scala> class C {
| def a: String = "a"
| }
defined class C
scala>
scala> trait T {
| def a: String
| }
defined trait T
scala>
scala> trait Q extends C with T {}
defined trait Q
- trait 中的方法實現(xiàn)了且與父類中的方法參數(shù)列表及返回類型相同:會沖突
scala> class C {
| def a: String = "a"
| }
defined class C
scala>
scala> trait T {
| def a: String = ""
| }
defined trait T
scala>
scala> trait Q extends C with T {}
<console>:9: error: trait Q inherits conflicting members:
method a in class C of type => String and
method a in trait T of type => String
(Note: this can be resolved by declaring an override in trait Q.)
trait Q extends C with T {}
^
- trait 中的方法實現(xiàn)了且與父類中的參數(shù)列表相同,返回類型不同:會沖突
scala> class C {
| def a: String = "a"
| }
defined class C
scala>
scala> trait T {
| def a: Int = 1
| }
defined trait T
scala>
scala> trait Q extends C with T {}
<console>:9: error: trait Q inherits conflicting members:
method a in class C of type => String and
method a in trait T of type => Int
(Note: this can be resolved by declaring an override in trait Q.)
trait Q extends C with T {}
^
- trait 中的方法實現(xiàn)了且與父類的參數(shù)列表不同铭段,返回類型相同:不會沖突
scala> class C {
| def a: String = "a"
| }
defined class C
scala>
scala> trait T {
| def a( i: Int ): String = i.toString
| }
defined trait T
scala>
scala> trait Q extends C with T {}
defined trait Q
trait 的繼承
一個 trait 同樣可以混入其他 trait 或繼承類:
scala> class C {
| def currentTime: String = System.currentTimeMillis().toString
| }
defined class C
scala>
scala> trait T {
| def random: Int
| }
defined trait T
scala>
scala> trait Q extends C with T {}
defined trait Q
雖然 Scala 語言支持你這么做骤宣,但我個人并不推薦
**傳送門: **Scala 在簡書目錄
歡迎關(guān)注我的微信公眾號:FunnyBigData