• Scala基础:面向对象之trait


    trait类似于java中的interface,但是有所不同

    • Scala中的trait是一种特殊的概念;
    • 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非常类似;
    • 在trait中可以定义抽象方法,就像抽象类中的抽象方法一样,只要不给出方法的方法体即可;
    • 类可以使用extends关键字继承trait,注意,这里不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends;
    • 类继承后,必须实现其中的抽象方法,实现时,不需要使用 override 关键字;
    • Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可。
    package com.zy.scala.trait_demo
    
    trait HelloTrait {
      def sayHello(): Unit
    }
    
    trait MakeFriendsTrait {
      def makeFriends(c: Children): Unit
    }
    
    //多重继承 trait
    class Children(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable {
      def sayHello() = println("Hello, " + this.name)
    
      def makeFriends(c: Children) = println("Hello, my name is " + this.name + ", your name is " + c.name)
    }
    
    object Children {
      def main(args: Array[String]) {
        val c1 = new Children("tom")
        val c2 = new Children("jim")
        c1.sayHello() //Hello, tom
        c1.makeFriends(c2) //Hello, my name is tom, your name is jim
      }
    }

    在trait中定义具体的方法

    Scala中的trait不仅可以定义抽象方法,还可以定义具体的方法,此时 trait 更像是包含了通用方法的工具,可以认为trait还包含了类的功能

    package com.zy.scala.trait_demo
    
    /**
      * 比如 trait 中可以包含很多子类都通用的方法,例如打印日志或其他工具方法等等。
      * spark就使用trait定义了通用的日志打印方法;
      */
    trait Logger {
      def log(message: String): Unit = println(message)
    }
    
    class PersonForLog(val name: String) extends Logger {
      def makeFriends(other: PersonForLog) = {
        println("Hello, " + other.name + "! My name is " + this.name + ", I miss you!!")
        this.log("makeFriends method is invoked with parameter PersonForLog[name = " + other.name + "]")
      }
    }
    
    object PersonForLog {
      def main(args: Array[String]) {
        val p1 = new PersonForLog("jack")
        val p2 = new PersonForLog("rose")
        p1.makeFriends(p2)
        //Hello, rose! My name is jack, I miss you!!
        //makeFriens method is invoked with parameter PersonForLog[name = rose]
      }
    }

    在trait中定义具体field

    • Scala 中的 trait 可以定义具体的 field,此时继承 trait 的子类就自动获得了 trait 中定义的 field;
    • 但是这种获取 field 的方式与继承 class 的是不同的。 如果是继承 class 获取的 field ,实际上还是定义在父类中的;而继承 trait获取的 field,就直接被添加到子类中了。
    package com.zy.scala.trait_demo
    
    trait PersonForField {
      val age: Int = 50
    }
    
    //继承 trait 获取的field直接被添加到子类中
    class StudentForField(val name: String) extends PersonForField {
      def sayHello = println("Hi, I'm " + this.name + ", my  age  is " + age)
    }
    
    object StudentForField {
      def main(args: Array[String]) {
        val s = new StudentForField("tom")
        s.sayHello
      }
    }

    在trait中定义抽象field

    • Scala中的trait也能定义抽象field, 而trait中的具体方法也能基于抽象field编写;
    • 继承trait的类,则必须覆盖抽象field,提供具体的值;
    package com.zy.scala.trait_demo
    
    trait SayHelloTrait {
      val msg: String
    
      def sayHello(name: String) = println(msg + ", " + name)
    }
    
    class PersonForAbstractField(val name: String) extends SayHelloTrait {
      //必须覆盖抽象 field
      val msg = "Hello"
    
      def makeFriends(other: PersonForAbstractField) = {
        this.sayHello(other.name)
        println("I'm " + this.name + ", I want to make friends with you!!")
      }
    }
    
    object PersonForAbstractField {
      def main(args: Array[String]) {
        val p1 = new PersonForAbstractField("Tom")
        val p2 = new PersonForAbstractField("Rose")
        p1.makeFriends(p2)
      }
    }

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

    • 可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有;
    • 在创建对象时,使用 with 关键字指定混入某个 trait; 
    package com.zy.scala.trait_demo
    
    trait LoggedTrait {
      // 该方法为实现的具体方法
      def log(msg: String) = {}
    }
    
    trait MyLogger extends LoggedTrait {
      // 覆盖 log() 方法
      override def log(msg: String) = println("log: " + msg)
    }
    
    class PersonForMixTraitMethod(val name: String) extends LoggedTrait {
      def sayHello = {
        println("Hi, I'm " + this.name)
        log("sayHello method is invoked!")
      }
    }
    
    object PersonForMixTraitMethod {
      def main(args: Array[String]) {
        val tom = new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom
        // 使用 with 关键字,指定混入MyLogger trait
        val rose = new PersonForMixTraitMethod("Rose") with MyLogger
        rose.sayHello
        // 结果为:     Hi, I'm Rose
        // 结果为:     log: sayHello method is invoked!
      }
    }

    trait 调用链

    • Scala中支持让类继承多个trait后,可依次调用多个trait中的同一个方法,只要让多个trait中的同一个方法,在最后都依次执行 super 关键字即可;
    • 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条;
    • 这种特性非常强大,其实就是设计模式中责任链模式的一种具体实现;
    package com.zy.scala.trait_demo
    
    trait HandlerTrait {
      def handle(data: String) = {
        println("last one")
      }
    }
    
    trait DataValidHandlerTrait extends HandlerTrait {
      override def handle(data: String) = {
        println("check data: " + data)
        super.handle(data)
      }
    }
    
    trait SignatureValidHandlerTrait extends HandlerTrait {
      override def handle(data: String) = {
        println("check signature: " + data)
        super.handle(data)
      }
    }
    
    class PersonForRespLine(val name: String) extends SignatureValidHandlerTrait with DataValidHandlerTrait {
      def sayHello = {
        println("Hello, " + this.name)
        this.handle(this.name)
      }
    }
    
    object PersonForRespLine {
      def main(args: Array[String]) {
        val p = new PersonForRespLine("tom")
        p.sayHello
        //执行结果:
        //    Hello, tom
        //    check data: tom
        //    check signature: tom
        //    last one
      }
    }

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

    • 在 trait 中,可以混合使用具体方法和抽象方法;
    • 可以让具体方法依赖于抽象方法,而抽象方法则可放到继承 trait的子类中去实现;
    • 这种 trait 特性,其实就是设计模式中的模板设计模式的体现;
    package com.zy.scala.trait_demo
    
    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)
      }
    }

    trait的构造机制

    • 在Scala中,trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
    • 继承了trait的子类,其构造机制如下:
    • 父类的构造函数先执行, class 类必须放在最左边;多个trait从左向右依次执行;构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;所有trait构造完毕之后,子类的构造函数最后执行。
    package com.zy.scala.trait_demo
    
    class Person_One {
      println("Person's constructor!")
    }
    
    trait Logger_One {
      println("Logger's constructor!")
    }
    
    trait MyLogger_One extends Logger_One {
      println("MyLogger's constructor!")
    }
    
    trait TimeLogger_One extends Logger_One {
      println("TimeLogger's contructor!")
    }
    
    class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
      println("Student's constructor!")
    }
    
    object exe_one {
      def main(args: Array[String]): Unit = {
        val student = new Student_One
        //执行结果为:
        //      Person's constructor!
        //      Logger's constructor!
        //      MyLogger's constructor!
        //      TimeLogger's contructor!
        //      Student's constructor!
      }
    }

    trait 继承 class

    package com.zy.scala.trait_demo
    
    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
      }
    }
  • 相关阅读:
    js学习笔记
    在 Windows 下远程桌面连接 Linux XManager 篇
    使用多种反病毒引擎扫描文件
    光纤接口小知识
    在 Windows 下远程桌面连接 Linux VNC 篇
    基于 RHEL 的 CentOS 5.5 发布
    安装Windows 7的XP模式的步骤
    跨平台加密版 SQLite 3 wxSQLite3
    Free 的迷思
    使用 iptables 限制黑客猜密码
  • 原文地址:https://www.cnblogs.com/blazeZzz/p/9794424.html
Copyright © 2020-2023  润新知