package ui
import observer._
//with关键字类似JAVA的implements关键字,但是和JAVA不同的是在声明多个traits时每个traits都要有属于自己的with
class ObservableButton(name: String) extends Button(name) with Subject {
override def click() = {//因为click()是覆盖父类Button的方法,这里不许使用override
super.click()
notifyObservers
}
}
//If you don’t use extends for the first trait, e.g., you write the following:
// ERROR:
class ObservableButton(name: String) with Button(name) with Subject {...}
[quote]
You’ll get an error like this:
... error: ';' expected but 'with' found.
class ObservableButton(name: String) with Button(name) with Subject {...}
[/quote]
注意:如果一个Class使用多个traits,但它没有继承其他Class时。第一个traits不能使用with关键字而要改成extends。
//trait中抽象方法或者类不需要加abstract
trait Clickable {
def click()
}
package ui2
import observer._
trait ObservableClicks extends Clickable with Subject {
//这里的方法为什么使用abstract?因为这里的方法体中使用了 super.click()但是它的父trait又没有实现click()方法。使用abstract告诉编译器这个方法没有完全实现。
abstract override def click() = {
super.click()
notifyObservers
}
}
package ui2
import org.specs._
import observer._
import ui.ButtonCountObserver
object ButtonClickableObserverSpec extends Specification {
"A Button Observer" should {
"observe button clicks" in {
val observableButton = new Button("Okay") with ObservableClicks
val buttonClickCountObserver = new ButtonCountObserver
observableButton.addObserver(buttonClickCountObserver)
for (i <- 1 to 3) observableButton.click()
buttonClickCountObserver.count mustEqual 3
}
}
}
//这里例子展示了在创建Button实例的时候混入了ObservableClicks。本来Button的实例是要求实现一个click()方法的,但是这个工作已经由ObservableClicks完成了。
package ui2
import org.specs._
import observer._
import ui.ButtonCountObserver
object ButtonClickableObserverVetoableSpec extends Specification {
"A Button Observer with Vetoable Clicks" should {
"observe only the first button click" in {
//ObservableClicks和VetoableClicks都实现了click()方法
//click()方法的覆盖顺序:右边trait的click方法覆盖左边trait的click方法
//即VetoableClicks.click()中调用super.click()将执行ObservableClicks.click()
val observableButton =
new Button("Okay") with ObservableClicks with VetoableClicks
val buttonClickCountObserver = new ButtonCountObserver
observableButton.addObserver(buttonClickCountObserver)
for (i <- 1 to 3) observableButton.click()
buttonClickCountObserver.count mustEqual 1
}
}
}
trait不支持辅助构造函数,也不支持带参数列表的主构造函数
trait能继承自Class和其他的trait
trait T1 {
println( " in T1: x = " + x )
val x=1
println( " in T1: x = " + x )
}
trait T2 {
println( " in T2: y = " + y )
val y="T2"
println( " in T2: y = " + y )
}
class Base12 {
println( " in Base12: b = " + b )
val b="Base12"
println( " in Base12: b = " + b )
}
class C12 extends Base12 with T1 with T2 {
println( " in C12: c = " + c )
val c="C12"
println( " in C12: c = " + c )
}
println( "Creating C12:" )
new C12
println( "After Creating C12" )
上面的代码的输出如下:
[quote]
Creating C12:
in Base12: b = null
in Base12: b = Base12
in T1: x = 0
in T1: x = 1
in T2: y = null
in T2: y = T2
in C12: c = null
in C12: c = C12
After Creating C12
[/quote]
这个例子中构造函数的执行顺序从Base12 到T1到T2,最后执行的是C12的构造函数。