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

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值