Scala概述(六)合成

6.       合成(composition

解釋了Scala的類型抽象體系之後本節主要描述類的合成方式譯註class composition似乎也沒有固定的譯法,此處翻譯成合成”)Scala的基於混入的類合成(mixin class composition)體系是Brach[6]中的面向對象的線性混入合成(linear mixin compostion)和[1425]中提出的更加對稱的混入模塊(mixin modules),以及traits[42]這三者的融合。(注:mixin有些人翻譯成混合,有些人翻譯成混入)我們先看一個例子,如下這個迭代器的抽象描述:

trait AbsIterator[T] {

def hasNext: boolean

def next: T

}

注意上面出現的關鍵字traitTrait是一種特殊的抽象類,他的構造子沒有任何值參數。Traits可以出現任何抽象類可以出現的地方,但反之不然,只有traits可以用於混入。

下面,我們用一個trait繼承自AbsIterator,並增加一個方法foreach,用於將一個函數作用於該迭代子返回的每一個元素上。

trait RichIterator[T] extends AbsIterator[T] {

def foreach(f: T => unit): unit =

while (hasNext) f(next)

}

下面是一個具體的迭代子類定義,用於連續返回一個字符串的每一個字符:

class StringIterator(s: String) extends AbsIterator[char] {

private var i = 0

def hasNext = i < s.length

def next = { val x = s charAt i; i = i + 1; x }

}

 

混入式類合成(Mixin-class composition下面我們將RichIteratorStringIterator的功能合併在一個類中。只有單根繼承和接口的情況下這是不可能的,因爲這兩個類都有具體的實現代碼。因此,Scala提供了混入式類合成的機制,使程序設計者可以重用一個類的增量內容,也就是非繼承的內容。這種機制使人可以將RichIteratorStringIterator合併,在如下所示的例子將一個字符串的所有字母打成一列。

object Test {

def main(args: Array[String]): unit = {

class Iter extends StringIterator(args(0))

with RichIterator[char]

val iter = new Iter

iter foreach System.out.println

}

}

Iter類通過RichIteratorStringIterator這兩個父類型混入合成,第一個父類型仍然稱爲超類(superclass),第二個父類型則稱爲混入(mixin)。

 

類的全序化(Class Linearization

混入式類合成是多重繼承的一種形式,因此也會面臨單繼承所沒有的問題。最典型的就是:如果多個父類型定義了同名的成員,哪一個成員被繼承?調用父類方法時那一個成員被引用?如果一個類從多個路徑被繼承了怎麼辦?在Scala中,解決這些問題的基礎構造就是類的全序化(class linearization)。(注:linearization可以翻成線性化或者全序化,在計算機領域一般取後者。另外,後面大部分情況下用全序來替代,主要是爲了讀起來不那麼彆扭)

一個類C所直接繼承的類形成的可遞閉包當中所有類稱爲C的基類(base classes)。由於有混入類,一個類與它的基類之間的繼承關係,構成一個有向無環圖(directed acyclic graph)。C的全序化L(C)C的所有基類的一個全序(total order),根據如下規則構成:假設C的定義爲:

class C extends B0 with . . . with Bn { . . . } .

這個全序以C的基類B0的全序爲最後一部分,前面是B1的全序(排除掉已經包含在B0的全序當中的類),再前面是B2…Bn,同樣排除掉前面已經出現過的類。最前面的是類C本身,作爲這個全序的頭一個類。例如,Iter類的全序化是:

{Iter, RichIterator, StringIterator, AbsIterator, AnyRef, Any }

類的全序對於類的繼承關係而言是一種改進:如果一個類CD的子類,則在任何同時繼承CD的類的全序中,C永遠出現在D之前。全序化還滿足另一個性質:一個類的全序永遠包括其基類的全序作爲後綴。例如,StringIterator的全序化:{ StringIterator, AbsIterator, AnyRef, Any }就是其子類Iter的全序的後綴。不過對於混入類,這個性質並不成立,一個混入類的全序當中的類,在其子類的全序當中可能以不同的順序出現,也就是說,Scala中全序化不是單調(monotonic[1])的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章