將Trait作為接口使用
Scala中的Triat是一種特殊的概念,可以將Trait作為接口來(lái)使用,此時(shí)的Triat就與Java中的接口非常類(lèi)似。在triat中可以定義抽象方法,就與抽象類(lèi)中的抽象方法一樣,只要不給出方法的具體實(shí)現(xiàn)即可;類(lèi)可以使用extends關(guān)鍵字繼承trait。注意這里不是implement而是extends。在scala中沒(méi)有implement的概念,無(wú)論繼承類(lèi)還是trait統(tǒng)一都是extends。類(lèi)繼承trait后,必須實(shí)現(xiàn)其中的抽象方法,實(shí)現(xiàn)時(shí)不需要使用override關(guān)鍵字。scala不支持對(duì)類(lèi)進(jìn)行多繼承,但是支持多重繼承trait,使用with關(guān)鍵字即可。
/**
* 定義人種接口
*/
trait Race{
/**
* 習(xí)俗,抽象方法
*/
def habitude():Unit
/**
* 祖先,抽象方法
*/
def ancestor():Unit
}
/**
* 人種實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)Race接口
*/
class RaceImpl(skin : String, lang : String) extends Race{
def habitude() : Unit = {
println("habitude 方法需在子類(lèi)中進(jìn)行實(shí)現(xiàn)")
}
def ancestor() : Unit = {
println("ancestor 方法需在子類(lèi)中進(jìn)行實(shí)現(xiàn)")
}
}
在Trait中定義具體方法
Scala中的Triat不只可以定義抽象方法,還可以定義具體方法,此時(shí)trait更像是包含了通用工具方法的"抽象類(lèi)"。有一個(gè)專有的名詞來(lái)形容這種情況,就是說(shuō)trait的功能混入了類(lèi)。
/**
* 定義人種接口
*/
trait Race{
//人種名稱,抽象field,需在繼承類(lèi)中覆蓋賦值
val raceName:String
//眼睛的數(shù)量,具體field
val eyes : Int = 2
//胳膊的數(shù)量,具體field
val arms : Int = 2
//腿的數(shù)量,具體field
val legs : Int = 2
/**
* 習(xí)俗
*/
def habitude():Unit
/**
* 祖先
*/
def ancestor():Unit
/**
* 睡覺(jué),具體方法
*/
def sleep()={
println("每天都要睡上一段時(shí)間")
}
}
定義具體字段
Scala中的Triat可以定義具體field,此時(shí)繼承trait的類(lèi)就自動(dòng)獲得了trait中定義的field。但是這種獲取field的方式與繼承class是不同的:如果是繼承class獲取的field,實(shí)際是定義在父類(lèi)中的;而繼承trait獲取的field,就直接被添加到了類(lèi)中。
定義抽象字段
Scala中的Triat可以定義抽象field,而trait中的具體方法則可以基于抽象field來(lái)編寫(xiě)。但是繼承trait的類(lèi)則必須覆蓋抽象field提供具體的值。
/**
* 人種實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)Race接口
*/
class RaceImpl(skin : String, lang : String) extends Race{
//覆蓋Trait中的raceName
val raceName:String = skin+"人種"
...
}
為實(shí)例混入trait
有時(shí)可以在創(chuàng)建類(lèi)的對(duì)象時(shí)指定該對(duì)象混入某個(gè)trait,這樣就只有這個(gè)對(duì)象混入該trait的方法,而類(lèi)的其他對(duì)象則沒(méi)有。
/**
* 喝茶trait
*/
trait Drink{
def tea()=println("喝茶")
}
...
val race1= new RaceImpl("黃色","漢語(yǔ)")
//race2混入Drink tait,可以調(diào)用tea()方法
val race2= new RaceImpl("黃色","漢語(yǔ)") with Drink
race1.ancestor()
race2.tea()
trait調(diào)用鏈
Scala中支持讓類(lèi)繼承多個(gè)trait后,依次調(diào)用多個(gè)trait中的同一個(gè)方法,只要讓多個(gè)trait的同一個(gè)方法中在最后都執(zhí)行super.方法即可。類(lèi)中調(diào)用多個(gè)trait中都有的這個(gè)方法時(shí),首先會(huì)從最右邊的trait的方法開(kāi)始執(zhí)行,然后依次往左形成一個(gè)調(diào)用鏈條。這種特性非常強(qiáng)大,相當(dāng)于設(shè)計(jì)模式中的責(zé)任鏈模式的一種具體實(shí)現(xiàn)。
/**
* 項(xiàng)目階段接口
*/
trait Phase {
//階段名稱,抽象字段
val phase : String
//每個(gè)階段做的事情,具體方法,空實(shí)現(xiàn)
def doSomething() : Unit = {}
}
/**
* 需求階段
*/
trait RequirementPhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "需求階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理需求階段相關(guān)事務(wù),如需求調(diào)研,編寫(xiě)需求文檔、需求評(píng)審等。")
super.doSomething()
}
}
/**
* 計(jì)劃階段
*/
trait PlanningPhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "計(jì)劃階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理計(jì)劃階段相關(guān)事務(wù),如編寫(xiě)里程碑計(jì)劃、開(kāi)發(fā)計(jì)劃、測(cè)試計(jì)劃,編寫(xiě)計(jì)劃文檔評(píng)審等。")
super.doSomething()
}
}
/**
* 設(shè)計(jì)階段
*/
trait DesignPhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "設(shè)計(jì)階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理設(shè)計(jì)階段相關(guān)事務(wù),如編寫(xiě)技術(shù)解決方案、概要設(shè)計(jì)、數(shù)據(jù)庫(kù)設(shè)計(jì),設(shè)計(jì)文檔評(píng)審等。")
super.doSomething()
}
}
/**
* 開(kāi)發(fā)階段
*/
trait DevelopmentPhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "開(kāi)發(fā)階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理開(kāi)發(fā)階段相關(guān)事務(wù),如編碼。")
super.doSomething()
}
}
/**
* 測(cè)試階段
*/
trait TestPhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "測(cè)試階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理測(cè)試階段相關(guān)事務(wù),如編寫(xiě)測(cè)試用例文檔、測(cè)試、編寫(xiě)測(cè)試報(bào)告、文檔評(píng)審等。")
super.doSomething()
}
}
/**
* 驗(yàn)收階段
*/
trait AcceptancePhase extends Phase {
//為trait抽象字段賦值
override val phase : String = "驗(yàn)收階段"
/**
* 實(shí)現(xiàn)trait中的抽象方法
*/
override def doSomething() : Unit = {
println("主要處理驗(yàn)收階段相關(guān)事務(wù),如開(kāi)發(fā)驗(yàn)收,文檔驗(yàn)收、項(xiàng)目交付等。")
super.doSomething()
}
}
/**
* 項(xiàng)目類(lèi),繼承各個(gè)階段的trait
*/
class Project extends AcceptancePhase
with TestPhase
with DevelopmentPhase
with DesignPhase
with PlanningPhase
with RequirementPhase {
//定義process方法
def process() : Unit = {
//調(diào)用trait中的方法
doSomething()
}
}
object Project{
def main(args: Array[String]): Unit = {
val p = new Project()
p.process()
}
}
在trait中覆蓋抽象方法
在trait中是可以覆蓋父trait的抽象方法的。覆蓋時(shí)如果使用了super.方法的代碼則無(wú)法通過(guò)編譯,因?yàn)閟uper.方法就會(huì)去掉用父trait的抽象方法,此時(shí)子trait的該方法還是會(huì)被認(rèn)為是抽象的。如果要通過(guò)編譯,就得給子trait的方法加上abstract override修飾。
混合使用具體方法和抽象方法
在trait中可以混合使用具體方法和抽象方法??梢宰尵唧w方法依賴于抽象方法,而抽象方法則放到繼承trait的類(lèi)中去實(shí)現(xiàn),這種trait其實(shí)就是設(shè)計(jì)模式中的模板設(shè)計(jì)模式的體現(xiàn)。
trait的構(gòu)造機(jī)制
在Scala中trait也是有構(gòu)造代碼的,也就是trait中的不包含在任何方法中的代碼。而繼承了trait的類(lèi)的構(gòu)造機(jī)制如下:
- 父類(lèi)的構(gòu)造函數(shù)執(zhí)行;
- trait的構(gòu)造代碼執(zhí)行,多個(gè)trait從左到右依次執(zhí)行;
- 構(gòu)造trait時(shí)會(huì)先構(gòu)造父trait,如果多個(gè)trait繼承同一個(gè)父trait,則父trait只會(huì)構(gòu)造一次;
- 所有trait構(gòu)造完畢之后,子類(lèi)的構(gòu)造函數(shù)執(zhí)行
繼承class
在Scala中trait也可以繼承自class,此時(shí)這個(gè)class就會(huì)成為所有繼承該trait的類(lèi)的父類(lèi)。