scala的trait设计

Scala的trait设计,突破了Java的object model的继承机制的限制,实际上变成了一种模块化的设计。

具体来讲,Trait并不是一个interface,而是一个功能模块,允许用户把这个模块插入到class当中。

例子如下:

scala> class ServiceImportante(name: String) {
     |   def work(i: Int): Int = {
     |     println(s"ServiceImportante: Doing important work! $i")
     |     i + 1
     |   }
     | }
defined class ServiceImportante
scala> val service1 = new ServiceImportante("uno")
service1: ServiceImportante = ServiceImportante@1c31408f
scala> (1 to 3) foreach (i => println(s"Result: ${service1.work(i)}"))
ServiceImportante: Doing important work! 1
Result: 2
ServiceImportante: Doing important work! 2
Result: 3
ServiceImportante: Doing important work! 3
Result: 4

如上所示,首先定义一个class,叫做ServiceImportante。然后定义一个叫做Logging的trait:

scala> trait Logging {
     |   def info   (message: String): Unit
     |   def warning(message: String): Unit
     |   def error  (message: String): Unit
     | }
defined trait Logging

trait本身也可以继承,方法也可以直接在trait里面实现:

scala> trait StdoutLogging extends Logging {
     |   def info   (message: String) = println(s"INFO:    $message")
     |   def warning(message: String) = println(s"WARNING: $message")
     |   def error  (message: String) = println(s"ERROR:   $message")
     | }
defined trait StdoutLogging

把trait作为功能模块插入到class当中:

scala> val service2 = new ServiceImportante("dos") with StdoutLogging {
     |   override def work(i: Int): Int = {
     |     info(s"Starting work: i = $i")
     |     val result = super.work(i)
     |     info(s"Ending work: i = $i, result = $result")
     |     result
     |   }
     | }
service2: ServiceImportante with StdoutLogging = $anon$1@674fee6d
scala> (1 to 3) foreach (i => println(s"Result: ${service2.work(i)}"))
INFO:    Starting work: i = 1
ServiceImportante: Doing important work! 1
INFO:    Ending work: i = 1, result = 2
Result: 2
INFO:    Starting work: i = 2
ServiceImportante: Doing important work! 2
INFO:    Ending work: i = 2, result = 3
Result: 3
INFO:    Starting work: i = 3
ServiceImportante: Doing important work! 3
INFO:    Ending work: i = 3, result = 4
Result: 4

scala>

如果要重复使用上面的ServiceImportante with StdoutLogging这个组合,也可以定义成一个新的class:

scala> class LoggedServiceImportante(name: String) extends ServiceImportante(name) with StdoutLogging
defined class LoggedServiceImportante

scala> val logged = new LoggedServiceImportante("logged")
logged: LoggedServiceImportante = LoggedServiceImportante@1d1bca3b

scala> logged.work(42)
ServiceImportante: Doing important work! 42
res15: Int = 43

以上。