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改写为类.
良好的面向对象设计要遵循下列的通用原则: 一旦完成构造过程,该实例便应一直处于某种已知的合法状态中.