快速學(xué)習(xí)Scala之接口

將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ī)制如下:

  1. 父類(lèi)的構(gòu)造函數(shù)執(zhí)行;
  2. trait的構(gòu)造代碼執(zhí)行,多個(gè)trait從左到右依次執(zhí)行;
  3. 構(gòu)造trait時(shí)會(huì)先構(gòu)造父trait,如果多個(gè)trait繼承同一個(gè)父trait,則父trait只會(huì)構(gòu)造一次;
  4. 所有trait構(gòu)造完畢之后,子類(lèi)的構(gòu)造函數(shù)執(zhí)行

繼承class

在Scala中trait也可以繼承自class,此時(shí)這個(gè)class就會(huì)成為所有繼承該trait的類(lèi)的父類(lèi)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第三節(jié)課主要是溝通技巧的應(yīng)用 課堂內(nèi)容分兩部分來(lái)講: 1、當(dāng)有人咨詢產(chǎn)品的時(shí)候,應(yīng)該這么去回答; 2、針對(duì)不同的人...
    黃志和閱讀 248評(píng)論 0 0
  • 吾日三省: 1.為什么人明知不對(duì)可依就沉溺于紙醉金迷,聲色犬馬之中,渾渾噩噩的度日。 2.真的是很難控制自己,要和...
    高能磷酸閱讀 367評(píng)論 0 0
  • 一個(gè)典型的項(xiàng)目結(jié)構(gòu) 項(xiàng)目結(jié)構(gòu)說(shuō)明 main.js聲明 Vue 項(xiàng)目的依賴。聲明 Vue 項(xiàng)目的入口( DOM 掛載...
    云之外閱讀 1,058評(píng)論 0 2

友情鏈接更多精彩內(nèi)容