The use of traits and trait conflicts in Scala

Description

  • In the Scala language, traits are used to replace the concept of interfaces. In other words, when multiple classes have the same characteristics, the characteristics can be separated and declared using the trait keyword.
  • In the characteristics of Scala, there can be both abstract attributes and abstract methods, as well as non-abstract attributes and non-abstract methods.
  • A class can be mixed with multiple traits.

Blend in single traits

object Scala03_Trait {
    
    
  def main(args: Array[String]): Unit = {
    
    
    val stu:PersonTrait03 = new Student03
    stu.sleep()
    stu.eat()
    println(stu.name)
  }
}


trait PersonTrait03 {
    
    
  // 特质中既可以有抽象属性和抽象方法
  var name: String
  def sleep(): Unit

  // 也可以有非抽象属性和非抽象方法
  var age: Int = 18
  def eat(): Unit = {
    
    
    println("Person eat")
  }
}

// 混入特质
class Student03 extends PersonTrait03 {
    
    

  // 重写特质中的抽象方法和属性
  override var name: String = "Li Ming"

  override def sleep(): Unit = {
    
    
    println("Student sleep")
  }
}

Mix in multiple traits

  • Mixing multiple traits without class inheritance: extends trait1 with trait2 with…
  • If there are class inheritance, mix in multiple traits, inherit the class first, then mix in traits: extends ClassName with trait1 with trait2…
  • When creating an object, dynamically mix in traits: new ClassName with trait1 {overwrite abstract method}.
object Scala04_Trait {
    
    
  def main(args: Array[String]): Unit = {
    
    
    /*val clzz = new MyClass04
    clzz.mA()
    val clazz1 = new MyClass004
    clazz1.mB()*/

    // 动态的混入特质
    val clzz004 = new MyClass004 with TraitC {
    
    
      override def mC(): Unit = {
    
    
        println("mC")
      }
    }
    clzz004.mC()
  }
}

trait TraitA {
    
    
  def mA(): Unit
}

trait TraitB {
    
    
  def mB(): Unit
}

trait TraitC {
    
    
  def mC(): Unit
}

class Super {
    
    
}

// 没有类继承的混入多个特质
class MyClass04 extends TraitA with TraitB with TraitC {
    
    
  override def mA(): Unit = {
    
    
    println("mA")
  }

  override def mB(): Unit = {
    
    
    println("mB")
  }

  override def mC(): Unit = {
    
    
    println("mC")
  }
}

// 有继承,混入多个特质。继承的类放在第一个位置
class MyClass004 extends Super with TraitA with TraitB{
    
    
  override def mA(): Unit = {
    
    
    println("mA")
  }

  override def mB(): Unit = {
    
    
    println("mB")
  }

}

Trait conflict (ordinary conflict)

  • When a class is mixed with multiple traits, if there is no relationship between the two traits, but there is an abstract method with the same name, the abstract method needs to be rewritten.
  • When a class is mixed with multiple traits, if there is no relationship between the two traits, but there is a non-abstract method with the same name, the non-abstract method needs to be rewritten.
object Scala05_Trait {
    
    
  def main(args: Array[String]): Unit = {
    
    
    val p = new Person05
    p.m1()

    val p2 = new Person005
    p2.m1()
  }
}

trait Person05TraitA {
    
    
  def m1(): Unit
}

trait Person05TraitB {
    
    
  def m1(): Unit
}

class Person05 extends Person05TraitA with Person05TraitB {
    
    
  override def m1(): Unit = {
    
    
    println("Person05中重写的m1方法")
  }
}

trait Person005TraitA {
    
    
  def m1(): Unit = {
    
    
    println("Person005TraitA m1")
  }
}

trait Person005TraitB {
    
    
  def m1(): Unit = {
    
    
    println("Person005TraitA m1")
  }
}

class Person005 extends Person005TraitA with Person005TraitB {
    
    
  override def m1(): Unit = {
    
    
    println("Person005中重写的m1方法")
  }
}

Trait stacking (diamond problem)

Insert picture description here

Description

Trait A and Trait B are mixed with Trait C. Trait A and Trait B both rewrite the m1 method in Trait C. A class mixes feature A and feature B at the same time, then which method is the m1 method in this class executed? This is the diamond problem.

Code

object Scala06_Trait {
    
    
  def main(args: Array[String]): Unit = {
    
    
    val operation = new MyOperation
    println(operation.m1())		// 我的操作是:向HDFS向数据库插入数据
  }
}

trait Operation {
    
    
  def m1(): String = {
    
    
    "插入数据"
  }
}

trait DBOperation extends Operation {
    
    
  override def m1(): String = {
    
    
    "向数据库" + super.m1()  }
}

trait HDFSOperation extends Operation {
    
    
  override def m1(): String = {
    
    
    "向HDFS" + super.m1()
  }
}

class MyOperation extends DBOperation with HDFSOperation with Operation {
    
    
  override def m1(): String = {
    
    
    "我的操作是:" + super.m1()
  }
}

Execution result analysis

  • The first step: List the inheritance relationship of the first trait mixed in as a temporary order.
    DBOperation --> Operation
  • Step 2: List the inheritance relationship of the second trait and superimpose the order before the order of the first trait. It should be noted that the traits that have already appeared will not be repeated.
    HDFSOperation --> DBOperation --> Operation
  • Step 3: Put the subcategory first in the temporary stacking sequence, which is the final stacking sequence.
    MyOperation --> HDFSOperation --> DBOperation --> Operation

Note: The super in the case does not mean its parent trait object, but the next trait in the above stacking sequence.

Guess you like

Origin blog.csdn.net/FlatTiger/article/details/114532029