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