將trait做爲接口使用設計模式
1 // Scala中的Triat是一種特殊的概念 2 // 首先咱們能夠將Trait做爲接口來使用,此時的Triat就與Java中的接口很是相似 3 // 在triat中能夠定義抽象方法,就與抽象類中的抽象方法同樣,只要不給出方法的具體實現便可 4 // 類可使用extends關鍵字繼承trait,注意,這裏不是implement,而是extends,在scala中沒有implement的概念,不管繼承類仍是trait,統一都是extends 5 // 類繼承trait後,必須實現其中的抽象方法,實現時不須要使用override關鍵字 6 // scala不支持對類進行多繼承,可是支持多重繼承trait,使用with關鍵字便可 7 8 trait HelloTrait { 9 def sayHello(name: String) 10 } 11 trait MakeFriendsTrait { 12 def makeFriends(p: Person) 13 } 14 class Person(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable { 15 def sayHello(name: String) = println("Hello, " + name) 16 def makeFriends(p: Person) = println("Hello, my name is " + name + ", your name is " + p.name) 17 }
在Trait中定義具體方法ide
1 // Scala中的Triat能夠不是隻定義抽象方法,還能夠定義具體方法,此時trait更像是包含了通用工具方法的東西// 有一個專有的名詞來形容這種狀況,就是說trait的功能混入了類 2 // 舉例來講,trait中能夠包含一些不少類都通用的功能方法,好比打印日誌等等,spark中就使用了trait來定義了通用的日誌打印方法 3 4 trait Logger { 5 def log(message: String) = println(message) 6 } 7 8 class Person(val name: String) extends Logger { 9 def makeFriends(p: Person) { 10 println("Hi, I'm " + name + ", I'm glad to make friends with you, " + p.name) 11 log("makeFriends methdo is invoked with parameter Person[name=" + p.name + "]") 12 } 13 }
在Trait中定義具體字段函數
1 // Scala中的Triat能夠定義具體field,此時繼承trait的類就自動得到了trait中定義的field 2 // 可是這種獲取field的方式與繼承class是不一樣的:若是是繼承class獲取的field,實際是定義在父類中的;而繼承trait獲取的field,就直接被添加到了類中 3 4 trait Person { 5 val eyeNum: Int = 2 6 } 7 8 class Student(val name: String) extends Person { 9 def sayHello = println("Hi, I'm " + name + ", I have " + eyeNum + " eyes.") 10 }
在Trait中定義抽象字段工具
// Scala中的Triat能夠定義抽象field,而trait中的具體方法則能夠基於抽象field來編寫 // 可是繼承trait的類,則必須覆蓋抽象field,提供具體的值 trait SayHello { val msg: String def sayHello(name: String) = println(msg + ", " + name) } class Person(val name: String) extends SayHello { val msg: String = "hello" def makeFriends(p: Person) { sayHello(p.name) println("I'm " + name + ", I want to make friends with you!") } }
爲實例混入traitspa
1 // 有時咱們能夠在建立類的對象時,指定該對象混入某個trait,這樣,就只有這個對象混入該trait的方法,而類的其餘對象則沒有 2 3 trait Logged { 4 def log(msg: String) {} 5 } 6 trait MyLogger extends Logged { 7 override def log(msg: String) { println("log: " + msg) } 8 } 9 class Person(val name: String) extends Logged { 10 def sayHello { println("Hi, I'm " + name); log("sayHello is invoked!") } 11 } 12 13 val p1 = new Person("leo") 14 p1.sayHello 15 val p2 = new Person("jack") with MyLogger 16 p2.sayHello
trait調用鏈scala
1 // Scala中支持讓類繼承多個trait後,依次調用多個trait中的同一個方法,只要讓多個trait的同一個方法中,在最後都執行super.方法便可 2 // 類中調用多個trait中都有的這個方法時,首先會從最右邊的trait的方法開始執行,而後依次往左執行,造成一個調用鏈條 3 // 這種特性很是強大,其實就至關於設計模式中的責任鏈模式的一種具體實現依賴 4 trait Handler { 5 def handle(data: String) {} 6 } 7 trait DataValidHandler extends Handler { 8 override def handle(data: String) { 9 println("check data: " + data) 10 super.handle(data) 11 } 12 } 13 trait SignatureValidHandler extends Handler { 14 override def handle(data: String) { 15 println("check signature: " + data) 16 super.handle(data) 17 } 18 } 19 class Person(val name: String) extends SignatureValidHandler with DataValidHandler { 20 def sayHello = { println("Hello, " + name); handle(name) } 21 } 22
在trait中覆蓋抽象方法設計
1 // 在trait中,是能夠覆蓋父trait的抽象方法的 2 // 可是覆蓋時,若是使用了super.方法的代碼,則沒法經過編譯。由於super.方法就會去掉用父trait的抽象方法,此時子trait的該方法仍是會被認爲是抽象的 3 // 此時若是要經過編譯,就得給子trait的方法加上abstract override修飾 4 5 trait Logger { 6 def log(msg: String) 7 } 8 9 trait MyLogger extends Logger { 10 abstract override def log(msg: String) { super.log(msg) } 11 } 12 13 14
混合使用trait的具體方法和抽象方法日誌
1 // 在trait中,能夠混合使用具體方法和抽象方法 2 // 可讓具體方法依賴於抽象方法,而抽象方法則放到繼承trait的類中去實現 3 // 這種trait其實就是設計模式中的模板設計模式的體現 4 5 trait Valid { 6 def getName: String 7 def valid: Boolean = { 8 getName == "leo" 9 } 10 } 11 class Person(val name: String) extends Valid { 12 println(valid) 13 def getName = name 14 } 15 16 17 18
trait的構造機制code
1 // 在Scala中,trait也是有構造代碼的,也就是trait中的,不包含在任何方法中的代碼 2 // 而繼承了trait的類的構造機制以下:一、父類的構造函數執行;二、trait的構造代碼執行,多個trait從左到右依次執行;三、構造trait時會先構造父trait,若是多個trait繼承同一個父trait,則父trait只會構造一次;四、全部trait構造完畢以後,子類的構造函數執行 3 4 class Person { println("Person's constructor!") } 5 trait Logger { println("Logger's constructor!") } 6 trait MyLogger extends Logger { println("MyLogger's constructor!") } 7 trait TimeLogger extends Logger { println("TimeLogger's constructor!") } 8 class Student extends Person with MyLogger with TimeLogger { 9 println("Student's constructor!") 10 } 11 12 13 14 15 16
trait field的初始化對象
1 // 在Scala中,trait是沒有接收參數的構造函數的,這是trait與class的惟一區別,可是若是需求就是要trait可以對field進行初始化,該怎麼辦呢?只能使用Scala中很是特殊的一種高級特性——提早定義 2 trait SayHello { 3 val msg: String 4 println(msg.toString) 5 } 6 7 class Person 8 val p = new { 9 val msg: String = "init" 10 } with Person with SayHello 11 12 class Person extends { 13 val msg: String = "init" 14 } with SayHello {} 15 16 // 另一種方式就是使用lazy value 17 trait SayHello { 18 lazy val msg: String = null 19 println(msg.toString) 20 } 21 class Person extends SayHello { 22 override lazy val msg: String = "init" 23 } 24 25 26 27
trait繼承class
1 // 在Scala中,trait也能夠繼承自class,此時這個class就會成爲全部繼承該trait的類的父類 2 3 class MyUtil { 4 def printMessage(msg: String) = println(msg) 5 } 6 7 trait Logger extends MyUtil { 8 def log(msg: String) = printMessage("log: " + msg) 9 } 10 11 class Person(val name: String) extends Logger { 12 def sayHello { 13 log("Hi, I'm " + name) 14 printMessage("Hi, I'm " + name) 15 } 16 } 17 18 19 20 21 22 23