`

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....

    scala-2.12.1 sdk

    scala 2.12.1 linux unix版

    Scala考试题1

    1.var,val和def三个关键字之间的区别 2.trait(特质)和abstract class(抽象类)的区别 3.object和class的区别 4.c

    Scala and Spark for Big Data Analytics.pdf

    Chapter 1, Introduction to Scala, will teach big data analytics using the Scalabased APIs of Spark. Spark itself is written with Scala and ... traits and trait linearization; and Java interoperability.

    Scala程序设计(第2版)

    3.14 Trait:Scala语言的接口和“混入” 83 3.15 本章回顾与下一章提要 85 第4章 模式匹配 86 4.1 简单匹配 86 4.2 match中的值、变量和类型 87 4.3 序列的匹配 90 4.4 元组的匹配 94 4.5 ...

    Scala—— 10.trait特质(接口)(未完待续)

    Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。理解trait等价于(interface+abstract class)。 1.trait的声明...

    Scala编程详解 第21讲-Scala编程详解:Actor入门 共8页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第19讲-Scala编程详解:类型参数 共13页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第4讲-Scala编程详解:条件控制与循环 共7页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第14讲-Scala编程详解:面向对象编程之继承 共13页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第13讲-Scala编程详解:面向对象编程之对象 共9页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第12讲-Scala编程详解:面向对象编程之类 共12页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    scala从入门到精通技术教学视频

    02.Scala程序和Java程序对比 03.Scala环境搭建 04.Scala解释器 05.案例_做最好的自己 第二章 变量和数据类型 00.导学 01.输出语句和分号 02.Scala中的常量 03.Scala中的变量 04.字符串的定义 05.惰性赋值 06.标识符 ...

    Scala编程详解 第8讲-Scala编程详解:函数入门之过程、lazy值和异常 共5页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala编程详解 第9讲-Scala编程详解:数组操作之Array、ArrayBuffer以及遍历数组 共7页.pptx

    第15讲-Scala编程详解:面向对象编程之Trait 共14页 第16讲-Scala编程详解:函数式编程 共14页 第17讲-Scala编程详解:函数式编程之集合操作 共9页 第18讲-Scala编程详解:模式匹配 共11页 第19讲-Scala编程详解:...

    Scala详细总结(精辟版++)

    这是我学习scala时做的...特质(trait) 19 显式类型转换 20 隐式转换、隐式参数 20 类型参数化 21 类型信息 22 集合 23 异常 27 断言、检查 27 包和引用 27 scala I/O 29 Actor和并发 29 GUI编程 31 结合scala和java 32

    Scala快速入门(适合为学Spark学习Scala的同学)

    scala安装使用、scala基础、scala方法与函数、scala tuple/集合/list/字符串/set/map、、trait特性、模式匹配、隐式转换、样例类、actorModal

    scala-2.9.2.jar

    import scala.annotation._ trait Func[T] { val zero: T def inc(t: T): T def dec(t: T): T def in: T def out(t: T): Unit } object ByteFunc extends Func[Byte] { override val zero: Byte = 0 ...

    Scala编程入门

    Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。 Scala 单作为一门语言来看, 非常的简洁高效 快速入门 在idea中集

    Scala for the Impatient 2nd (完整英文第二版 带书签)

    《快学Scala》英文第二版: Scala for the Impatient Second Edition Cay S. Horstmann 目录: 1 THE BASICS A1 1 1.1 The Scala Interpreter 1 1.2 Declaring Values and Variables 4 1.3 Commonly Used Types 5 ...

Global site tag (gtag.js) - Google Analytics