Scala --- 面向對象編程之trait特質

介紹:

  • trait特質 是 Scala中代碼複用的基礎單元 (相當於java的接口)
  • 作用:他可以將方法和字段定義封裝起來,然後添加到類中
  • 與類的區別:每個類只能繼承一個超類,而一個類可以添加任意數量的特質 ;
  • 使用方法: 使用extends 來繼承trait  ; 如果要繼承多個trait,則使用with關鍵字                                                    class ConsoleLogger2 extends Logger2 with MessageSender

eg1:繼承單個trait  Logger1.scala

trait Logger1 {
  // 抽象方法
  def log(msg:String)
}

class ConsoleLogger1 extends Logger1 {
  override def log(msg: String): Unit = println(msg)
}

object LoggerTrait1 {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger1
    logger.log("控制檯日誌: 這是一條Log")
  }
}

eg2:繼承多個trait   

trait Logger2 {
  // 抽象方法
  def log(msg:String)
}

trait MessageSender {
  def send(msg:String)
}

class ConsoleLogger2 extends Logger2 with MessageSender {

  override def log(msg: String): Unit = println(msg)

  override def send(msg: String): Unit = println(s"發送消息:${msg}")
}

object LoggerTrait2 {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger2
    logger.log("控制檯日誌: 這是一條Log")
    logger.send("你好!")
  }
}

//輸出:
控制檯日誌: 這是一條Log
發送消息:你好!

定義具體的方法

  • 和類一樣,trait中還可以定義具體的方法
trait LoggerDetail {
  // 在trait中定義具體方法
  def log(msg:String) = println(msg)
}

class PersonService extends LoggerDetail {
  def add() = log("添加用戶")
}

object MethodInTrait {
  def main(args: Array[String]): Unit = {
    val personService = new PersonService
    personService.add()
  }
}

定義具體方法和抽象方法

  • 在trait中,可以混合使用具體方法和抽象方法
  • 使用具體方法依賴於抽象方法,而抽象方法可以放到繼承trait的子類中實現,這種設計方式也稱爲模板模式
trait Logger3 {
  // 抽象方法
  def log(msg:String)
  // 具體方法(該方法依賴於抽象方法log
  def info(msg:String) = log("INFO:" + msg)
  def warn(msg:String) = log("WARN:" + msg)
  def error(msg:String) = log("ERROR:" + msg)
}

class ConsoleLogger3 extends Logger3 {
  override def log(msg: String): Unit = println(msg)
}

object LoggerTrait3 {
  def main(args: Array[String]): Unit = {
    val logger3 = new ConsoleLogger3

    logger3.info("這是一條普通信息")
    logger3.warn("這是一條警告信息")
    logger3.error("這是一條錯誤信息")
  }
}

//輸出 :
INFO:這是一條普通信息
WARN:這是一條警告信息
ERROR:這是一條錯誤信息

定義具體字段和抽象字段

  • 在trait中可以定義具體字段和抽象字段
  • 繼承trait的子類自動擁有trait中定義的字段
trait LoggerEx {
  // 具體字段
  val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm")
  val INFO = "信息:" + sdf.format(new Date)
  // 抽象字段
  val TYPE:String

  // 抽象方法
  def log(msg:String)
}

class ConsoleLoggerEx extends LoggerEx {
  // 實現抽象字段
  override val TYPE: String = "控制檯"
  // 實現抽象方法
  override def log(msg:String): Unit = print(s"$TYPE$INFO $msg")
}

object FieldInTrait {
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLoggerEx

    logger.log("這是一條消息")
  }
}

//輸出:
控制檯信息:2019-12-04 14:58 這是一條消息

實例對象混入trait

  • trait還可以混入到實例對象中,給對象實例添加額外的行爲    new UserService with LoggerMix
  • 只有混入了trait的對象才具有trait中的方法,其他的類對象不具有trait中的行爲
  • 使用with將trait混入到實例對象中
trait LoggerMix {
  def log(msg:String) = println(msg)
}

class UserService

object FixedInClass {
  def main(args: Array[String]): Unit = {
    // 使用with關鍵字直接將特質混入到對象中
    val userService = new UserService with LoggerMix

    userService.log("你好")
  }
}

//輸出:
你好

trait調用鏈

責任鏈模式:

  • 類繼承了多個trait後,可以依次調用多個trait中的同一個方法,只要讓多個trait中的同一個方法在最後都依次執行super關鍵字即可。
  • 類中調用多個tait中都有這個方法時,首先會從最右邊的trait方法開始執行,然後依次往左執行,形成一個調用鏈條
// 支付數據處理
trait HandlerTrait {
  def handle(data: String) = {
    println("處理數據...")
  }
}

// 數據校驗處理
trait DataValidHandlerTrait extends HandlerTrait {
  override def handle(data: String) = {
    println("驗證數據...")
    super.handle(data)
  }
}

// 簽名校驗處理
trait SignatureValidHandlerTrait extends HandlerTrait {
  override def handle(data: String) = {
    println("檢查簽名...")
    super.handle(data)
  }
}

// 支付服務
class PaymentService extends DataValidHandlerTrait with SignatureValidHandlerTrait {
  def pay(data:String) = {
    println("準備支付...")
    //類繼承了多個trait後,可以依次調用多個trait中的同一個方法
    this.handle(data)
  }
}

object PaymentService {
  def main(args: Array[String]) {
    val payService = new PaymentService()
    payService.pay("signature:10233123||md5:123889a3d5s1f6123||data:{order:001,money:200}")
  }
}

//輸出:
準備支付...
檢查簽名...
驗證數據...
處理數據...

trait的構造機制:

trait也有構造代碼,但和類不一樣,特質不能有構造器參數 (每個特質只有一個無參數的構造器 )

一個類繼承另一個類、以及多個trait,當創建該類的實例時,它的構造順序 :

  • 1、執行父類的構造器

  • 2、從左到右依次執行trait的構造器

  • 3、如果trait有父trait,先構造父trait,如果多個trait有同樣的父trait,則只初始化一次

  • 4、執行子類構造器

class Person_One {
  println("執行Person構造器!")
}
trait Logger_One {
  println("執行Logger構造器!")
}
trait MyLogger_One extends Logger_One {
  println("執行MyLogger構造器!")
}
trait TimeLogger_One extends Logger_One {
  println("執行TimeLogger構造器!")
}
class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
  println("執行Student構造器!")
  }
object exe_one {
  def main(args: Array[String]): Unit = {
    val student = new Student_One
  }
}

//輸出:
執行Person構造器!
執行Logger構造器!
執行MyLogger構造器!
執行TimeLogger構造器!
執行Student構造器!

trait繼承class:

  • trait也可以繼承class

  • 這個class就會成爲所有該trait子類的超級父類

class MyUtil {
  def printMsg(msg: String) = println(msg)
}
trait Logger_Two extends MyUtil {
  def log(msg: String) = this.printMsg("log: " + msg)
}
class Person_Three(val name: String) extends Logger_Two {
    def sayHello {
        this.log("Hi, I'm " + this.name)
        this.printMsg("Hello, I'm " + this.name)
  }
}
object Person_Three{
  def main(args: Array[String]) {
      val p=new Person_Three("Tom")
      p.sayHello
    //執行結果:
//      log: Hi, I'm Tom
//      Hello, I'm Tom
  }
}

//輸出:
log: Hi, I'm Tom
Hello, I'm Tom

 

 

發佈了124 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章