7.4 Trait方法的延迟绑定

上面的例子里,Check类的check()方法是具体的,trait都是从这个类继承来的。我们见识到了,在trait里对super.check()的调用是如何绑定到其左边的trait或是其混入的类的。但如果基类的方法是抽象的,就会变得有点复杂。下面进一步探索一番。

先写一个抽象类Writer,它有一个抽象方法writeMessage()

TraitsAndTypeConversions/MethodBinding.scala

  1. abstract class Writer {
  2. def writeMessage(message: String)
  3. }

任何继承这个类的类都要实现writeMessage()方法。如果有一个trait继承了这个抽象类,并且用super调用了这个抽象方法,Scala会要求将方法声明为abstract override。将这两个关键字组合到一起看上去有些奇怪。关键字override告诉Scala,要为基类的一个已知方法提供一个实现。同时,还表示,这个方法实际最后的“终极”实现由混入这个trait的类提供。下面是一个例子,这个trait继承了上面的那个类:

TraitsAndTypeConversions/MethodBinding.scala

  1. trait UpperCaseWriter extends Writer {
  2. abstract override def writeMessage(message: String) =
  3. super.writeMessage(message.toUpperCase)
  4. }
  5. trait ProfanityFilteredWriter extends Writer {
  6. abstract override def writeMessage(message: String) =
  7. super.writeMessage(message.replace("stupid", "s-----"))
  8. }

在这段代码里,为了调用super.writeMessage,Scala做了两件事。首先,它对这个调用进行了延迟绑定。其次,它会要求混入这些trait的类提供该方法的实现。ProfanityFilteredWriter只负责处理有些粗鲁的单词——且仅当它以小写形式出现。这是为了体现混入的顺序。

现在来用一下这些trait。先来写一个类StringWriterDelegate,继承自抽象类Writer,将写消息的操作委托给一个StringWriter实例:

TraitsAndTypeConversions/MethodBinding.scala

  1. class StringWriterDelegate extends Writer {
  2. val writer = new java.io.StringWriter
  3. def writeMessage(message: String) = writer.write(message)
  4. override def toString() : String = writer.toString
  5. }

在上面StringWriterDelegate的定义里可以混入一个或多个trait,不过,在这里,我们选择的是在创建这个类的实例时混入trait。

TraitsAndTypeConversions/MethodBinding.scala

  1. val myWriterProfanityFirst =
  2. new StringWriterDelegate with UpperCaseWriter with ProfanityFilteredWriter
  3. val myWriterProfanityLast =
  4. new StringWriterDelegate with ProfanityFilteredWriter with UpperCaseWriter
  5. myWriterProfanityFirst writeMessage "There is no sin except stupidity"
  6. myWriterProfanityLast writeMessage "There is no sin except stupidity"
  7. println(myWriterProfanityFirst)
  8. println(myWriterProfanityLast)

在第一个语句里,ProfanityFilteredWriter是最右的trait,所以,它会先起作用。然而,在第二个语句中,它会后起作用。这段代码可能需要花些时间研究一下。这两个实例的方法执行顺序如图7-1所示:

7.4 Trait方法的延迟绑定 - 图1

图7-1 两个实例的方法执行顺序

输出如下:

  1. THERE IS NO SIN EXCEPT S-----ITY
  2. THERE IS NO SIN EXCEPT STUPIDITY