介紹:
- 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