`

Scala 有趣的Trait

阅读更多

(转自http://www.qqread.com/other-devtool/f484284.html)

与Java相似之处

Scala类型系统的基础部分是与Java非常相像的。Scala与Java一样有单一的根类,Java通过接口来实现多重继承,而Scala则通过特征(trait)来实现(Scala的特征可以包含实现代码,这当然是与Java接口不同的。不过由于特征自己具有类型的功能,所以对于没有包含实现代码的特征,可以认为与Java的接口是等价的)

用Trait来实现混入(mix-in)式的多重继承

Scala里相当于Java接口的是Trait(特征)。Trait的英文意思是特质和性状(本文称其为特征),实际上他比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。Scala中特征被用于服务于单一目的功能模块的模块化中。通过混合这种特征(模块)群来实现各种应用程序的功能要求,Scala也是按照这个构想来设计的。

一般情况下Scala的类只能够继承单一父类,但是如果是特征的话就可以继承多个,从结果来看就是实现了多重继承。就看一下下面的例子吧。为了辨认方便,此后的特征名称前都加上前缀字母T。特征既可以继承类也可以继承其他特征。

  1. class Person ; //实验用的空类
  2. trait TTeacher extends Person {  
  3. def teach //虚方法,没有实现  
  4. }  
  5. trait TPianoPlayer extends Person {  
  6. def playPiano = {println("I’m playing piano. ")} //实方法,已实现  
  7. }  
  8. class PianoplayingTeacher extends Person with TTeacher with TPianoPlayer {  
  9. def teach = {println("I’m teaching students. ")} //定义虚方法的实现  
  10. }  
如上所示,可以连着多个with语句来混合多个特征到一个类中。第一个被继承源用extends,第二个以后的就用with语句。正如大家所知道的,可以生成实例的是非抽象(abstract)的类。另外请注意一下从特征是不可以直接创建实例的。

那么就实际运行一下吧。

 

  1. scala> val t1 = new PianoplayingTeacher  
  2. t1: PianoplayingTeacher = PianoplayingTeacher@170a650 
  3. scala> t1.playPiano  
  4. I’m playing piano.  
  5. scala> t1.teach  
  6. I’m teaching students.  
实际上如下所示,可以在创建对象时才将特征各自的特点赋予对象。

 

 

  1. scala> val tanakaTaro = new Person with TTeacher with TPianoPlayer {  
  2. | def teach = {println("I'm teaching students.")} }  
  3. tanakaTaro: Person with TTeacher with TPianoPlayer = $anon$1@5bcd91 
  4. scala> tanakaTaro playPiano  
  5. I’m playing piano.  
  6. scala> tanakaTaro teach  
  7. I'm teaching students.  
用特征来方便地实现面向方面的编程

 

充分利用特征的功能之后,就能方便地实现现今流行的面向方面编程(AOP)了。

首先,用特征来声明表示基本动作方法的模块Taction。

 

  1. trait TAction {  
  2. def doAction  
  3. }  
接着作为被加入的方面,定义一下加入了前置处理和后置处理的特征TBeforeAfter。

 

 

  1. trait TBeforeAfter extends TAction {  
  2. abstract override def doAction {  
  3. println("/entry before-action") //doAction的前置处理  
  4. super.doAction // 调用原来的处理  
  5. println("/exit after-action") //doAction的后置处理  
  6. }  
  7. }  
通过上面的abstract override def doAction {}语句来覆盖虚方法。具体来说这当中的super.doAction是关键,他调用了TAction的doAction方法。其原理是,由于doAction是虚方法,所以实际被执行的是被调用的实体类中所定义的方法。

 

那么将实际执行的实体类RealAction作为TAction的子类来实现吧。

 

  1. class RealAction extends TAction {  
  2. def doAction = { println("** real action done!! **") }  
  3. }  
接着就执行一下。

 

 

  1. scala> val act1 = new RealAction with TBeforeAfter  
  2. act1: RealAction with TBeforeAfter = $anon$1@3bce70 
  3. scala> act1.doAction  
  4. /entry before-action  
  5. ** real action done!! **  
  6. /exit after-action  
仅仅这样还不好玩,接着为他定义一下别的方面,然后将这些方面加入到同一对象的方法中。接着定义一个将源方法执行两遍的方面。

 

 

  1. trait TTwiceAction extends TAction {  
  2. abstract override def doAction {  
  3. for ( i <- 1 to 2 ) { // 循环执行源方法的方面  
  4. super.doAction // 调用源方法doAction  
  5. println( " ==> No." + i )  
  6. }  
  7. }  
  8. }  
下面,将TBeforeAfter和TtwiceAction混合在一起后执行一下。

 

 

  1. scala> val act2 = new RealAction with TBeforeAfter with TTwiceAction  
  2. act2: RealAction with TBeforeAfter with TTwiceAction = $anon$1@1fcbac1 
  3. scala> act2.doAction  
  4. /entry before-action  
  5. ** real action done!! **  
  6. /exit after-action  
  7. ==> No.1 
  8. /entry before-action  
  9. ** real action done!! **  
  10. /exit after-action  
  11. ==> No.2 
伴随着原来方法的before/after动作一起各自执行了两次。接着将混入顺序颠倒后再试一下。

 

 

  1. scala> val act3 = new RealAction with TTwiceAction with TBeforeAfter  
  2. act3: RealAction with TTwiceAction with TBeforeAfter = $anon$1@6af790 
  3. scala> act3.doAction  
  4. /entry before-action  
  5. ** real action done!! **  
  6. ==> No.1 
  7. ** real action done!! **  
  8. ==> No.2 
  9. /exit after-action  

 

这样执行后,原来的实现方法被循环执行了两次,但是before/after则在循环以外整体只执行了一次。这是根据with语句定义的顺序来执行的,知道了这原理之后也就没有什么奇怪的了。Scala特性的如此混入顺序是和AspectJ的方面以及Spring的interceptor相同的。

这样不仅是before和after动作,只要更改了特征的实现就可以将各种方面动态地加入到原来的对象中去了,读者自己也可以尝试一下各种其他情况。

在Java中通过Decorator或Template Method模式来想尽办法实现的功能,在Scala中只要通过特征就可以轻松到手了。从这还可以延展开来,通过在原来的方法中插入挂钩的方法,即所谓的拦截者式面向方面的方法,就可以轻松地将各个方面通过特征来组件化了。

请读者如果想起Scala是怎样的强类型和静态化语言的话,那么就能够明白通过特征来加入新功能的特点给他带来了多大的灵活性。

分享到:
评论
1 楼 chainal 2018-02-11  
赞,说的很好

相关推荐

    Scala Trait(特质).html

    Scala Trait(特征) 1.Scala中没有接口(interface)的概念 2.特质用于在类之间共享程序接口和字段,类似Java接口 3.特质是字段和方法的集合,可以提供字段和方法实现 4.类和单例对象都可以扩展特质(extends) 5....

    scala3 scala3 scala3 scala3 scala3

    Scala3通过`trait`的`sealed`修饰符和`object`的`opaque`修饰符来鼓励更严格的封装。`sealed`特质限制了其子类只能在定义的文件或模块内存在,`opaque`对象则使得类型可以有私有的实现细节,对外只暴露必要的接口。 ...

    scala sdk scala-2.12.3

    8. **面向对象编程**:Scala支持传统的类、继承、封装和多态性,同时也引入了特质(trait),可以用来实现混合类型和行为。 9. **函数式编程**:函数在Scala中是一等公民,可以作为参数传递,也可以作为返回值。...

    scala2.12.1Windows镜像包

    - **面向对象**:支持类、接口、继承和多态,同时引入了特质(trait),提供了一种灵活的实现多重继承的方式。 - **函数式编程**:函数是一等公民,可以作为参数传递,也可以作为返回值。并支持高阶函数、柯里化、...

    scala-2.12.1 sdk

    Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性,使得开发者能够在同一平台上享受到两种编程范式的优点。标题"scala-2.12.1 sdk"表明我们正在讨论的是Scala的软件开发工具包(SDK),版本为...

    scala-2.12.8 源码包

    6. ** Trait**:Scala的Trait是类似于接口的结构,但可以包含具体实现。它们用于实现多继承和行为组合。源码中可以学习Trait的实现细节。 7. **类型推断**:Scala的类型推断使得编写简洁的代码成为可能,编译器会...

    最好的scala学习 课件

    Scala支持类、对象、继承、封装和多态,同时引入了特质(trait),它允许你实现多重继承的效果。这部分还会讲解伴生对象(companion object)和隐式转换,这些特性使得Scala的面向对象设计更加灵活。 "Scala进阶之...

    Scala考试题1

    Scala 是一种多范式的编程语言,它融合了面向对象和函数式编程的特性。下面将详细解释题目中涉及的Scala知识点: 1. **var、val 和 def 的区别**: - `var` 定义可变变量,可以多次赋值。 - `val` 定义不可变变量...

    scala学习笔记整理

    5. ** Trait**:Scala的Trait类似于Java的接口,但可以包含实现,允许多重继承。Trait是实现行为组合的重要手段,有助于避免“菱形问题”。 6. ** Actors模型**:Scala内置对Akka框架的支持,提供了一种基于Actors...

    Scala Cookbook

    8. ** Trait和Mixins**:Scala的trait允许代码重用和组合,形成灵活的模块化设计,书中将解释如何有效地使用trait。 9. **Lambda表达式和匿名函数**:Scala支持函数作为一等公民,书中的内容会涵盖如何使用lambda...

    学习scala好的项目

    例如,`case class`用于创建模式匹配友好的数据结构,而`trait`则提供了接口和混入(mix-in)多重继承的功能。此外,`Option`类型是Scala处理null安全的一种方式,它强制程序员明确处理空值情况,避免了常见的...

    scala学习源代码

    此外,Scala还引入了特质(trait),它类似于接口,但可以包含实现,提供了更灵活的多态性。 函数式编程是Scala的另一大特色。它支持高阶函数,即可以接受函数作为参数或返回函数的函数。函数是第一类公民,意味着...

    scala-2.11.12 win msi 安装包

    3. **面向对象**:Scala支持传统的面向对象编程,包括类、对象、继承和封装等概念,同时引入了特质(trait),增强了多继承的能力。 4. **函数式编程**:Scala深受函数式编程语言如Lisp和Haskell的影响,支持高阶...

    scala 案例

    7. ** Trait**:Scala的Trait类似于Java的接口,但可以包含抽象方法的实现,可以用来实现多重继承和代码复用。 8. ** Scalactic 和 ScalaTest**:Scalactic是用于定义和操作质量值的库,而ScalaTest是一个广泛使用...

    Scala-2.11.1.zip

    不过,它还引入了特质(trait),这是一种更轻量级的继承方式,可以用来实现多重继承和混合行为。 3. **函数式编程**:Scala是函数式编程的强大平台,它提供了高阶函数、匿名函数、柯里化、尾递归优化等功能。函数...

    Scala中文版

    2. **面向对象**:Scala支持类和对象,同时也引入了特质(trait),这是一种轻量级的继承方式,可以用来实现多重继承和混合行为。 3. **函数式编程**:Scala提供了丰富的高阶函数和不可变数据结构,使得编写纯函数...

    Programming In Scala 中文版及英文版

    《Programming In Scala》是一本权威的Scala编程语言教程,它由Martin Odersky(Scala的创造者)、Lex Spoon 和 Bill Venners 共同编写。中文版包含了1到13章的内容,这些章节涵盖了Scala的基础知识和基本应用,适合...

    Scala语言规范.zip

    6. ** Trait**:Scala的trait是一种可复用的代码块,可以包含字段和方法,可以被类混合进来实现多继承。Trait的使用有助于避免传统继承带来的问题。 7. **模式匹配**:Scala的模式匹配功能强大,可以用于解构复杂...

    Scala编程书合集

    通过阅读这本规范,开发者可以直接了解语言的底层机制,解决在编程过程中遇到的特定问题,或者为了更深入地理解Scala的某些特性,比如类型推断、特质(trait)和宏(macro)。 接下来是《Programming in Scala》的...

Global site tag (gtag.js) - Google Analytics