Simple Scala: Traits

Java 8中的接口

Java8中,可以在接口中定义方法,被称为defender方法或默认方法,实现类仍然可以提供自己的实现.如果实现类未提供实现,则会调用defender方法.这种行为更接近于Scala中的trait.

但是不同之处在于,Java8中只能定义静态字段,而trait则可以定义实例级字段.因此Java中的接口无法管理实例状态,接口实现类必须提供字段以记录状态.这也意味着defender方法无法访问接口实现体的状态信息,从而限制了defender的用途.

Trait

包含抽象方法的trait并不需要声明为抽象对象,无需再trait之前添加abstract关键字.但是,包含一个或多个未定义方法的类,则必须声明为抽象类.

Scala使用线性化(linearization)算法解决具体类继承树中trait和类的优先级问题.其优先级遵循从右到左的原则.

构造Trait

Trait并不允许为其提供参数列表,也无法为其提供辅助构造函数.

Trait可以继承自其它的特质,用于也可以继承自类,但是无法向其父类提供构造函数传递参数,字面量参数也不例外.因此,trait只能扩展自那些包含了无参主构造函数或无辅助构造函数的类.

像类一样,每次创建使用了trait的实例时,特质实体都会被执行.因此,尽管不能想trait传递构造参数,但是可以在特质体内初始化字段,方法和类型.线性化算法允许声明中后续列出的trait或类覆写这些定义.

不要在trait中声明那些无法在初始化时指定合适默认值的具体字段.如果需要声明这类字段,使用抽象字段,或者将该trait改写为含有构造函数的类.对于那些不包含状态信息的trait而言,初始化时不会遇到这些问题.

Trait和类的选择

特质是Scala实现混入的方式,适用于大多数的辅助行为.

如果发现某一特定的trait在大多数时候被用作其他类的父类,那么这些子类表现的就像这个父特质一样.为了使逻辑更加清晰,此时应该考虑是否应该把这个trait改写为类.

良好的面向对象设计要遵循下列的通用原则: 一旦完成构造过程,该实例便应一直处于某种已知的合法状态中.