早上研究了Scala的trait与abstract class的区别,大体有以下几点:
-
抽象类代表一个独立的实体,trait代表一个具体的功能,不能独立存在;
-
如果希望多个彼此无关的类复用一项相同的功能,把它用trait实现;
-
一个类只能继承(使用
extensds
关键字)一个抽象类, 但可以mixin(使用with
关键字)多个trait,可以同时使用, 例如下面实例中的class D extends B with C
; -
抽象类可以有类型参数(通过使用
type
关键字)和构造函数参数, trait只能有类型参数; -
trait可以继承自(
extends
)其他trait; -
trait可以继承自(
extends
)抽象类,例如下面的trait C extends A
; -
当无法确定使用trait还是抽象类时,优先使用trait;
实例代码1:
abstract class A {
val message: String
}
class B extends A {
val message = "I'm an instance of class B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
class D extends B with C
val d = new D
d.message // I'm an instance of class B
d.loudMessage // I'M AN INSTANCE OF CLASS B
mixin的栈特性(stackable):
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1@6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1@188c838
scala> yx.a
X
Y
res1: Int = 1
讨论
2013年在广州开发GODU时,曾经设计过这样的类结构:
接口 > 抽象类 > 多个具体实现类。
之所以要在接口和具体实现类之间插入一个抽象类层,
就是因为有一些通用的方法实现不能写在接口里,如果放在具体实现类里,
又会出现大量的冗余,但这样的3层结构,导致最上面的接口被架空,只能作为名义上的行为规范。
如果用Scala实现,就可以把通用功能放在trait里面实现,
各个具体实现类 MyConcreteClass1 extends MyInterface with MyTrait
就可以了。
参考:
-
https://stackoverflow.com/questions/1991042/what-is-the-advantage-of-using-abstract-classes-instead-of-traits
-
https://stackoverflow.com/questions/2005681/difference-between-abstract-class-and-trait
-
http://docs.scala-lang.org/tutorials/tour/mixin-class-composition.html.html