Scala09——Scala面向对象编程之特质trait

1、将trait作为接口使用

在 Scala中Trait 为重用代码的一个基本单位。
将traits作为Java中的接口使用,一个 Traits 封装了方法和变量(但和 Interface 相比,它的方法可以有实现,这一点有点和抽象类定义类似)。
但和类继承不同的是,Scala 中类继承为单一继承,子类只能有一个父类。但一个类可以和多个 Trait 混合,使用 with 关键字即可。这些 Trait 定义的成员变量和方法也就变成了该类的成员变量和方法。
类可以使用extends关键字继承trait,(这里不是 implement,而是extends) ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
由此可以看出 Trait 集合了 Interface 和抽象类的优点,同时又没有破坏单一继承的原则。

package com.fgm.traits

trait SpeakTrait {
  def speak:Unit
}

trait EatingTrait{
  val eating="food is meat"
}

abstract class Animal{
  val age=10
  def running:Unit
}
//可以单继承类Animal,可以和多个trait混合
class Dog(val name:String ) extends Animal with SpeakTrait with EatingTrait{
  override def speak: Unit = {
    println("wangwangwang")
  }

  def running: Unit = {
    println("He is running ")
  }
}
object Dog{
  def main(args: Array[String]): Unit = {
    val dog = new Dog("一条狗")
    println(dog.name)
    dog.speak
    dog.running
    println(dog.age)
    println(dog.eating)
  }
}

2、trait中定义具体的方法和field

Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能。
trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
从trait中获取field的方式与继承class获得field的方式不同:
–继承 class 获取的 field ,实际上还是定义在父类中的;
–而继承 trait获取的 field,就直接被添加到子类中。

3、trait中定义抽象的方法和field

Scala中的trait也能定义抽象方法和抽象field, 而trait中的具体方法也能基于抽象field编写
继承trait的类,则必须覆盖抽象方法和抽象field,提供具体的值;

package com.fgm.traits

trait SayHello {
  val msg:String
  def sayHello(name: String) = println(msg + name)
  def say:Unit
}

class TraitTest02(val name: String) extends SayHello{
  //必须覆盖抽象 field
  val msg = "Hello"
  def makeFriends(other: TraitTest02) = {
    this.sayHello(other.name)
    println("I'm " + this.name + ", I want to make friends with you")
  }
  //必须覆盖抽象方法
  override def say: Unit = {
    println("this is the method to override abstract method ")
  }
}
object TraitTest02{
  def main(args: Array[String]) {
    val p1=new TraitTest02("Tom")
    val p2=new TraitTest02("Jerry")
    p1.makeFriends(p2)
    //输出结果:HelloJerry
	//I'm Tom, I want to make friends with you
  }
}

4、在实例对象中指定混入某个trait

可在创建类的对象时,使用 with 关键字为该对象指定混入某个trait。
且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;

package com.fgm.traits

trait LogTrait {
  // 该方法为实现的具体方法
  def log(msg: String) = {}
}
trait MyLogger extends LogTrait{
  // 覆盖 log() 方法
  override def log(msg: String) = println("log: " + msg)
}

class MixTrait(val name: String) extends LogTrait {
  def sayHello = {
    println("Hi, I'm " + this.name)
    log("I'm the trait method")
  }
}
object MixTrait{
  def main(args: Array[String]) {
    
    val tom= new MixTrait("Tom")
    //结果为:Hi, I'm Tom
    tom.sayHello 
    
    // 使用 with 关键字,指定混入MyLogger trait
    val rose = new MixTrait("Rose") with MyLogger
    // 输出结果为:Hi, I'm Rose
    // 输出结果为:log: I'm the trait method
    rose.sayHello
    
  }
}

5、trait 调用链

Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
这是设计模式中责任链模式的一种具体实现;

6、混合使用 trait 的具体方法和抽象方法

在 trait 中,可以混合使用具体方法和抽象方法:可以让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现;
这是设计模式中的模板设计模式的体现;

trait ValidTrait {
 //抽象方法
  def getName: String     
//具体方法,具体方法的返回值依赖于抽象方法
                        
 def valid: Boolean = {"Tom".equals(this.getName)
  }
}
class PersonForValid(val name: String) extends ValidTrait {
  def getName: String = this.name
}

object PersonForValid{
  def main(args: Array[String]): Unit = {
    val person = new PersonForValid("Rose")
    println(person.valid)
  }
}

7、trait的构造机制

在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
继承了trait的子类,其构造机制如下:
父类的构造函数先执行, class 类必须放在最左边;
多个trait从左向右依次执行;
构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;
所有trait构造完毕之后,子类的构造函数最后执行。

class Person {
  println("Person's constructor!")
}
trait Logger {
  println("Logger's constructor!")
}
trait MyLogger extends Logger {
  println("MyLogger's constructor!")
}
trait TimeLogger extends Logger {
  println("TimeLogger's contructor!")
}
class Student extends Person with MyLogger with TimeLogger {
  println("Student's constructor!")
  }
object exe {
  def main(args: Array[String]): Unit = {
    val student = new Student
    //执行结果为:
//      Person's constructor!
//      Logger's constructor!
//      MyLogger's constructor!
//      TimeLogger's contructor!
//      Student's constructor!
  }
}

该案例中:
(1)在构建class类Student的对象时,其父类Person的构造函数先执行。
(2)之后MyLogger 和TimeLogger 按照顺序从左到右依次执行,也就是先构造trait MyLogger ,由于MyLogger 继承了Logger,所以,在构造MyLogger 时,先构造它的父trait,也就是Logger的构造方法接着执行;
(3)在MyLogger 的父trait Logger 构造执行之后,MyLogger 的构造函数开始执行;
(4)接下来,按照从左到右的顺序,执行TimeLogger ,TimeLogger 也有父trait ,但它的父trait和MyLogger的父trait相同,按照“多个trait继承同一个父trait,则父trait只会构造一次”的原则,这里不再执行Logger的构造函数,所以直接执行TimeLogger 的构造函数。
(5)所有trait构造完毕之后,子类的构造函数最后执行。此时发现所有trait的构造函数均已执行完毕,所以此时执行子类Student的构造函数。

8、trait 继承 class

在Scala中trait 也可以继承 class,此时这个 class 就会成为所有继承该 trait 的子类的超级父类.

9、一些已定义好的trait

Ordered:Ordered特质扩展自java的Comparable接口,Ordered特质用于排序,为了使用它,首先将其混入类中,然后实现一个compare方法。
源码参考:

trait Ordered[A] extends Any with java.lang.Comparable[A] {

  /** Result of comparing `this` with operand `that`.
   *
   * Implement this method to determine how instances of A will be sorted.
   *
   * Returns `x` where:
   *
   *   - `x < 0` when `this < that`
   *
   *   - `x == 0` when `this == that`
   *
   *   - `x > 0` when  `this > that`
   *
   */
  def compare(that: A): Int

  /** Returns true if `this` is less than `that`
    */
  def <  (that: A): Boolean = (this compare that) <  0

  /** Returns true if `this` is greater than `that`.
    */
  def >  (that: A): Boolean = (this compare that) >  0

  /** Returns true if `this` is less than or equal to `that`.
    */
  def <= (that: A): Boolean = (this compare that) <= 0

  /** Returns true if `this` is greater than or equal to `that`.
    */
  def >= (that: A): Boolean = (this compare that) >= 0

  /** Result of comparing `this` with operand `that`.
    */
  def compareTo(that: A): Int = compare(that)
}

object Ordered {
  /** Lens from `Ordering[T]` to `Ordered[T]` */
  implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
    new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
}

Ordering
Application
APP

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值