序言
上一次对比Java说明了Scala的特点和类定义的方法。这一次将更加深入一点,还是以迷你旅行的方式探险一下Scala的语法特点。
接下来介绍一下用代替Java接口的特征(Trait)来实现的混入(mix-in)多重继承、类型层次和集合。
用特征来实现混入(mix-in)式的多重继承
Scala里相当于Java接口的是特征(Trait)。Trait的英文意思是特质和性状(本文称其为特征),实际上他比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。Scala中特征被用于服务于单一目的功能模块的模块化中。通过混合这种特征(模块)群来实现各种应用程序的功能要求,Scala也是按照这个构想来设计的。
一般情况下Scala的类只能够继承单一父类,但是如果是特征的话就可以继承多个,从结果来看就是实现了多重继承。这可以被认为是同Ruby模块基本相同的功能。就看一下下面的例子吧。为了辨认方便,此后的特征名称前都加上前缀字母T。特征既可以继承类也可以继承其他特征。
class Person ; trait TTeacher extends Person { def teach } trait TPianoPlayer extends Person { def playPiano = {println("I’m playing piano. ")} } class PianoplayingTeacher extends Person with TTeacher with TPianoPlayer { def teach = {println("I’m teaching students. ")} } |
如上所示,可以连着多个with语句来混合多个特征到一个类中。第一个被继承源用extends,第二个以后的就用with语句。正如大家所知道的,可以生成实例的是非抽象(abstract)的类。另外请注意一下从特征是不可以直接创建实例的。
那么就实际运行一下吧。
scala> val t1 = new PianoplayingTeacher t1: PianoplayingTeacher = PianoplayingTeacher@170a650 scala> t1.playPiano I’m playing piano. scala> t1.teach I’m teaching students. |
实际上如下所示,可以在创建对象时才将特征各自的特点赋予对象。
scala> val tanakaTaro = new Person with TTeacher with TPianoPlayer { | def teach = {println("I'm teaching students.")} } tanakaTaro: Person with TTeacher with TPianoPlayer = $anon$1@5bcd91 scala> tanakaTaro playPiano I’m playing piano. scala> tanakaTaro teach I'm teaching students. |
用特征来方便地实现面向方面的编程
充分利用特征的功能之后,就能方便地实现现今流行的面向方面编程(AOP)了。
首先,用特征来声明表示基本动作方法的模块Taction。
trait TAction { def doAction } |
接着作为被加入的方面,定义一下加入了前置处理和后置处理的特征TBeforeAfter。
trait TBeforeAfter extends TAction { abstract override def doAction { println("/entry before-action") super.doAction println("/exit after-action") } } |