scala学习手记34 - trait方法的延迟绑定

trait的方法的延迟绑定就是先混入的trait的方法会后调用。这一点从上一节的实例中也可以看出来。

下面再来看一个类似的例子:

abstract class Writer {
  def write(message: String): String
}

trait UpperWriter extends Writer {
  abstract override def write(message: String): String = super.write(message.toUpperCase)
}

trait FilterWriter extends Writer {
  abstract override def write(message: String): String = super.write(message.replace(‘o‘, ‘-‘))
}

trait StringWriter extends Writer {
  def write(message: String): String = message
}

val myWriter1 = new StringWriter with UpperWriter with FilterWriter

val myWriter2 = new StringWriter with FilterWriter with UpperWriter

println(myWriter1 write "Hello World!")

println(myWriter2 write "Hello World!")

在代码中定义了一个抽象类和三个trait。

其中抽象类Writer仅定义了一个抽象方法,并没有提供具体的实现。因此继承抽象类Writer的trait必须要实现write方法。

UpperWriter的write方法实现了将传入的英文字符转为大写;

FilterWriter的write方法实现了将小写的“o”替换为“-”;

StringWriter则只是将传入的字符串原样返回。

看一下上面的代码的执行结果:

验证了我们的说法:延迟绑定就是先混入的trait会后执行。

myWriter1的执行顺序:FilterWriter –> UpperWriter –> StringWriter;

myWriter2的执行顺序:UpperWriter –> FilterWriter –> StringWriter。

从trait的延迟绑定很容易会想到java的父类与子类的初始化顺序。又或者是java中的责任链模式。因此想想用java来实现这一点并不难:可以采用不同顺序的责任链,也可以是使用不同的继承顺序来实现。

再者,从这两节可以看出来scala中的trait和抽象类并无多大差别:

  1. 都可以有普通方法和抽象方法;
  2. 都可以有普通成员变量和抽象变量;
  3. 抽象类能做的事情trait都能做。

那他们的差别在哪儿呢:

  • trait可以多重混入,抽象类只能单继承;
  • 抽象类可以定义构造函数;
  • trait可以混入实例,抽象类不可以。

那什么时候用trait,什么时候用抽象类呢:

  • 优先使用trait。一个类扩展多个trait是很方便的,但却只能扩展一个抽象类。
  • 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而trait不行。例如,你不能说trait t(i: Int) {},参数i是非法的。

参考文档:

https://twitter.github.io/scala_school/zh_cn/basics.html

http://stackoverflow.com/questions/1991042/what-is-the-advantage-of-using-abstract-classes-instead-of-traits

http://www.artima.com/pins1ed/traits.html#12.7

##############

时间: 2024-10-27 09:34:10

scala学习手记34 - trait方法的延迟绑定的相关文章

scala学习手记31 - Trait

不知道大家对java的接口是如何理解的.在我刚接触到接口这个概念的时候,我将接口理解为一系列规则的集合,认为接口是对类的行为的规范.现在想来,将接口理解为是对类的规范多少有些偏颇,更恰当些的观点应该是:相对于类来说,接口是更深层次的抽象,虽然同时接口也起到了规定类的行为的作用. 和java的接口比起来,scala的Trait可能更具体一些.正如Trait的含义一样,它指的是一种特质,如果认为类有某种特质就混入对应的Trait好了.在scala中,类是对现实某一类事务的建模,而Trait则是对已有

scala学习手记20 - 方法返回类型推断

除了推演变量的类型,scala也会推演方法的返回类型.不过这里有一处需要注意:方法返回类型的推演依赖于方法的定义方式.如果用等号"="定义方法,scala就会推演方法返回类型:否则,它就认为方法的返回为void.看一个例子: def printMethodInfo(methodName: String) { println("The return type of " + methodName + " is " + getClass().getDe

scala学习手记13 - 类继承

在scala里,类继承有两点限制: 重写方法需要使用override关键字: 只有主构造函数才能往父类构造函数中传参数. 在java1.5中引入了override注解,但不强制使用.不过在scala中要想重写方法必须使用override关键字.如果确实重写了父类的方法又不使用override关键字的话,则会在编译时报错,提示没有使用override修饰符. scala的副构造函数必须调用主构造函数或是另一个副构造函数.只有在主构造函数中才能向父类的构造函数中传递数据.可以看出来主构造函数如同父类

scala学习手记2 - scala中的循环

先来看一段Java中的循环: for (int i = 1; i < 4; i++) { System.out.print(i + ","); } 毫无疑问,scala可以让这个循环更加简洁.根据上一节中的内容,没有必要显示指定变量i的类型,我们甚至不需要声明这个变量.其次输出的语句也可以更加简洁一些,在scala中可以直接使用println()这个方法输出字符串.最后scala的循环结构也是非常的轻量级.好了,可以看一下代码了: for (i <- 1 to 3) { p

PHP OPP 和模式 (2) - 静态变量、属性和方法及延迟绑定

PHP高级程序设计 学习笔记 2014.06.10 本文讨论static关键字,他可以用在变量.类和方法上. 1.静态变量 静态变量是只存在于函数作用域的变量,不过,在函数执行完成以后,这种变量的值不会丢失,也就是说,在下一次执行这个函数时,变量仍然会记得原来的值.要将某个变量定义为静态的,只需要在变量前加上static关键字即可. function testing() { static $a = 1; $a *= 2; echo $a."\n"; } testing(); testi

scala学习手记38 - 方法命名约定和for表达式

方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. 比如下面这个例子: class Cow { def ^(moon: Moon) = println("Cow jumped over the moon") } class Moon { def ^:(cow: Cow) = println("This cow jumped ove

scala学习手记12 - 字段、方法和构造函数

在上一节创建了一个scala类,如果没有更多的方法,scala类的定义还可以更简单一些,看一下下面这个CreditCard类的定义: class CreditCard(val number: Int, var creditLimit: Int) 是的,只用一行就完成了类的定义,连大括号都不需要. 因为scala也是运行在JVM上,可以考虑以java的方式来看看编译后的类文件.查看的方式还是比较灵活的,可以使用JD-GUI,也可以使用javap –private CreditCard命令,还有一个

scala学习手记8 - 自适应的默认做法

scala有一些默认做法,会让代码更简洁.更易读写,下面列出了这样几个特性: 1. 支持脚本.scala支持脚本,因此无须将所有的代码都放到类里.如果脚本可以满足需求,就将代码放到一个脚本里,无须再创建一个冗余的类. 2. return是可选的.如果没有写return关键字,方法调用会自动返回最后一个求值的表达式--如果它符合方法声明的返回值类型. 3. 分号":"是可选的.不必在每个语句的后面都写上分号,这样会使代码更简洁.如果语句太长或者包含多行的话可以换行继续写,scala能够识

scala学习手记23 - 函数值

scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子:从1到某个数求和.使用Java很容易实现: int sum(int max){ int result = 0; for (int i = 0; i <= max; i++) { result +=i; } return result; } 使用scala实现也没有多大区别. 现在再扩展下需求:对某