Scala特质(特征)Trait
场景简介
例:
某助教(TeachingAssistant.class)。他既是学生(Student.class)也是员工(Employee.class)。
理想情况是:
class Student { def id: String = ... ... } class Employee { def id: String = ... ... } // 提醒:这是无法实现的多重继承示例 Class TeachingAssistant extends Student, Employee { ··· }
问题来了:scala和java一样不允许类从多个超类继承,但为什么不能有多重继承呢?
如果是 毫不相干 的多个类,多重继承只是把他们组合在一起,只要实现各自类中的方法就没问题。但如上面的例子所示,TeachingAssistant类继承了两个id方法,这显然是有冲突和混乱的(调用助教对象中的id方法时,无法确定返回学生id还是员工id)
再复杂些,假定Student类和Employee类都扩展自同一个超类Person:
class Person { var name: String = _ } class Student extends Person { ... } class Employee extends Person { ... }
这就引出了菱形继承问题
Teaching Assistant中的name字段要如何合并呢?又如何被构造呢?——扩展知识:C++的“虚拟基类”
Java的解决办法是采取强限制策略来规避这种使用:类只能扩展自一个超类;它可以实现任意数量的接口【但接口只能包含抽象方法,不能包含字段**Java8的特性中允许接口包含静态方法static和默认方法default,只是看起来似乎违反了接口作为一个抽象定义的理念】
Scala提供“特质”而非接口来解决这个问题。
特质比java接口更强大
首先,特质最大的特点就是可以同时拥有抽象方法和具体方法,与此同时一个基类可以像实现接口一样实现多个特质。
// 例如有一个Logger的特质(包含抽象方法) trait Logger { // 这是个抽象方法(但不需要用abstract特别声明,因为特质中没有实现的方法默认就是抽象的) def log(msg: String): Unit } // 子类可以给出具体实现 // 用的是extends,而不是implements class ConsoleLogger extends Logger { // 不需要写override,写上也没事 def log(msg: String): Unit = { println(msg) } } // --------------------------------我是分割线----------------------------------------- // 再例如有一个ConsoleLogger的特质(包含具体方法) trait ConsoleLogger { def log(msg: String): Unit = { println(msg) } } // 子类使用ConsoleLogger class SavingsAccount extends Account with ConsoleLogger { // 当账单金额大于余额时,显示账户余额不足,否则正常扣款 def withdraw (amount: Double) { // 这里直接调用了ConsoleLogger特质中的log方法来实现 if (amount > balance) log("Insufficient funds") else