Introduction to Scala's Trait

Basic concepts

In Scala language, trait is used to replace the concept of interface, that is, multiple classes have the same
When the trait (feature) of the is selected, the trait (feature) can be independent and declared with the keyword trait.
The trait in Scala can have either abstract attributes and methods or concrete attributes and methods. A class can
To mix in multiple traits. This feeling is similar to abstract classes in Java.
Scala introduces the trait feature. First, it can replace the Java interface. Second, it is also a single inheritance mechanism
Supplement.

Trait statement

Basic grammar

trait Trait name { 
 trait subject 
} 

Use of traits

If a class has a certain trait (feature), it means that the class meets all the elements of the trait (feature). Therefore, the extends keyword is also used. If there are multiple traits or parent classes, you need to use with
Keyword connection.

Basic grammar

No parent class: class Class name extends Trait 1 with Trait 2 with Trait 3 
There are parent classes: class Class name extends Parent class with Trait 1 with Trait 2 with Trait 3 

explain

(1) Relationship between class and trait: use inheritance relationship.
(2) When a class inherits traits, the first connective is extends, followed by with.
(3) If a class inherits attributes and parent classes at the same time, the parent class should be written after extensions.

Case practice

(1) Traits can have both abstract and concrete methods
(2) A class can mix in multiple traits
(3) All Java interfaces can be used as Scala features

package chapter06

object Test13_Trait {
  def main(args: Array[String]): Unit = {
    val student: Student13 = new Student13

    student.sayHello()
    student.study()
    student.dating()
    student.play()
  }



}

//Define parent class
class Person13{
  val name: String = "person"
  val age: Int = 18

  def sayHello(): Unit = {
    println("hello")
  }

  def increase():Unit ={
    println("increased")
  }
}

//Define a trait
trait Young{

  //Declare an abstract and non Abstract property and method

  val age: Int
  val name : String = "young"

  //Define abstract and non abstract methods
  def play(): Unit = {
    println("I can play")
  }

  def dating(): Unit
}

class Student13 extends Person13 with Young{

  //Override conflicting properties
  override val name : String = "student"


  //Implement abstract methods
  override def dating(): Unit = {
    println("Student is dating")
    println(s"student : $name")
  }

  def study(): Unit = {
    println("student is study")
  }

  //Override parent method
  override def sayHello(): Unit = {
    println("student say hello")

  }

}

Trait superposition

Basic concepts

Because a class can mix multiple traits, and there can be specific attributes and methods in the traits, if the mixed traits have the same methods (method name, parameter list and return value are the same), inheritance conflict will inevitably occur.
There are two types of conflicts:
First, a class (Sub) has the same concrete method in two traits (TraitA, TraitB) mixed with it, and
There is no relationship between the two trait s. To solve this kind of conflict, override the conflict method directly in the class (Sub).

Second, a class (Sub) has the same concrete method in two traits (TraitA, TraitB) mixed with it, and
The two traits inherit from the same trait (TraitC) and the so-called "Diamond problem" to solve this kind of conflict problem, Scala
The strategy of trait superposition is adopted.

The so-called trait superposition is the superposition of conflicting methods in multiple traits

Case practice

(4) Dynamic blending: flexible extension of class functions

  • Dynamic blending: when creating an object, you blend the trait without having to mix the class into the trait
  • If there are unimplemented methods in the mixed trait, they need to be implemented
package chapter06

object Test14_TriatMixin {
  def main(args: Array[String]): Unit = {

    val student = new Student14

    student.study()
    student.increase()

    student.play()
    student.increase()

    student.dating()
    student.increase()

    println("==========================")

    //Trait dynamic blending
    val studentWithTalent = new Student14 with Talent {

      override def singing(): Unit = {
        println("student is good at singing")
      }
    }

    studentWithTalent.play()
    studentWithTalent.dating()
    studentWithTalent.study()
    studentWithTalent.singing()


  }

}

//Define another trait
trait Knowledge{

  var amount : Int = 0
  def increase(): Unit
}

//Another trait
trait Talent{
  def singing(): Unit

}

class Student14 extends Person13 with Young with Knowledge {

  //Override conflicting properties
  override val name : String = "student"


  //Implement abstract methods
  override def dating(): Unit = {
    println("Student is dating")
    println(s"student : $name")
  }

  def study(): Unit = {
    println("student is study")
  }

  //Override parent method
  override def sayHello(): Unit = {
    println("student say hello")

  }

  //Abstract methods of realizing traits
  override def increase(): Unit = {
    amount += 1

    println(s"student $name knowledge increased: $amount")

  }

}

Trait overlay execution sequence

When a class is mixed with multiple traits, scala will classify all traits and their parent traits in a certain order
sort

Case description

package chapter06

object Test15_TraitOverlying {
  def main(args: Array[String]): Unit = {

      println(new MyBall().describe()) 


  }

}
trait Ball { 
   def describe(): String = { 
      "ball" 
   } 
} 
 
trait Color extends Ball { 
   override def describe(): String = { 
      "blue-" + super.describe() 
   } 
} 
 
trait Category extends Ball { 
   override def describe(): String = { 
      "foot-" + super.describe() 
   } 
} 
 
class MyBall extends Category with Color { 
   override def describe(): String = { 
      "my ball is a " + super.describe() 
   } 
}

In this case, super What is called by describe() is actually the describe() in the next trait in the order
Method, the sorting rules are as follows:


Step 1: list the inheritance relationship of the first mixed Category as the temporary superposition order

Step 2: list the inheritance relationship of the mixed second Color, and overlay the order to the front of the temporary order. The existing characteristics will not be repeated

Step 3: put the subclass (MyBall) first in the temporary stacking order to get the final stacking order

Conclusion:
(1) super in the case does not represent its parent trait object, but the next trait in the above superposition sequence,
That is, super in MyClass refers to Color, super in Color refers to Category, and super in Category refers to Ball.
(2) If you want to call a specified method mixed into the trait, you can add a constraint: Super [], such as super[Category].describe().

Trait self type

explain

Its own type can realize the function of dependency injection.

Case practice

package chapter06

object Test16_TraitSelfType {
  def main(args: Array[String]): Unit = {

    val user = new RegisterUser("alice","password123")

    user.insert

  }

}

//User class
class User(val name: String, val password: String)

//Database operation class
trait UserDao{
  _: User =>

  //Insert data into database
  def insert: Unit = {

    println(s"insert into db: ${this.name}")

  }
}

//Registered user class
class RegisterUser(name: String, password: String) extends User(name,password) with UserDao {

  println("A user is registered")

}

Difference between trait and abstract class

  1. Give priority to traits. It is convenient for a class to extend multiple characteristics, but it can only extend one abstract class.
  2. If you need constructor parameters, use abstract classes. Because abstract classes can define constructors with parameters, but not characteristics (with or without parameters).

Keywords: Scala

Added by i on Sat, 01 Jan 2022 02:45:13 +0200