1. 程式人生 > >Scala入門2(特質與疊加在一起的特質)

Scala入門2(特質與疊加在一起的特質)

區別 混入 {} abs 它的 pan rac 特征 有一個

一、介紹

  參考http://luchunli.blog.51cto.com/2368057/1705025

  我們知道,如果幾個類有某些共通的方法或者字段,那麽從它們多重繼承時,就會出現麻煩。所以Java被設計成 不支持多重繼承,但可以實現任意多的接口。接口只能包含抽象方法,不能包含字段。

  特質 trait 是Scala中特有的一項特點,不同於C#與Java,如果一定要拿C#與Java中的某項特點作對比的話,最接近的應該是接口,但是C#與Java中的接口是不允許帶有方法實現的,而Scala中的Trait是可以帶有方法實現的。這樣做的好處需要某個trait就拿來用,而不需要重復實現接口

  所有的Java接口都可以作為Scala特質來使用。與Java一樣,Scala類只能有一個超類,可以有任意數量的特質。

  特質的定義使用保留字trait,具體語法與類定義類似,除了不能擁有構造參數

1 trait reset {
2     def reset (m : Int, n : Int) = if (m >= n) 1;
3 }

  一旦特質被定義了,就可以混入到類中

1 class week extends reset {......}

  當要混入多個特質時,利用with保留字

1 class week extends reset with B with C {......}

  特質的成員可以是抽象的,而且不需要使用abstract聲明。同樣,重寫特質的抽象方法無需給出override。但是,多個特質重寫同一個特質的抽象方法需要給出override。
  除了在類定義中混入特質外,還可以在特質定義中混入特質

1 trait reseting extends reset {......}

  在對象構造時混入特質

1 val file = new month with reseting

  特質的構造是有順序的,從左到右被構造

 1 /**
 2  * @author lucl
 3  */
 4 class Teacher {  // 實驗用的空類
 5   println("===============I‘m Teacher.");
 6 }  
 7  
 8 trait TTeacher extends Teacher {
 9   println("===============I‘m TTeacher.")
10 def teach; // 虛方法,沒有實現 11 } 12 13 trait TPianoTeacher extends Teacher { 14 println("===============I‘m TPianoTeacher.") 15 def playPiano = { // 實方法,已實現 16 println("I‘m playing piano."); 17 } 18 } 19 20 class PianoPlayingTeacher extends Teacher with TTeacher with TPianoTeacher { 21 println("===============I‘m PianoPlayingTeacher.") 22 def teach = { // 定義虛方法的實現 23 println("I‘m teaching students."); 24 } 25 } 26 27 object TraitOps { 28 def main (args : Array[String]) { 29 var p = new PianoPlayingTeacher; 30 p.teach; 31 p.playPiano; 32 } 33 } 34 35 /** 36 ===============I‘m Teacher. 37 ===============I‘m TTeacher. 38 ===============I‘m TPianoTeacher. 39 ===============I‘m PianoPlayingTeacher. 40 I‘m teaching students. 41 I‘m playing piano. 42 */

二、例子

  我們的例子中定義了一個抽象類Aminal表示所有的動物,然後定義了兩個trait Flyable和Swimable分別表示會飛和會遊泳兩種特征。

  Aminmal的實現(定義了walk方法,實現了breathe方法)

1 abstract class Animal {
2   def walk(speed : Int);
3    
4   def breathe () = {
5     println("animal breathes.");
6   }
7 }

  Flyable和Swimable兩個 trait的實現

 1 /**
 2  * @author lucl
 3  * 有兩個方法,一個抽象方法一個已實現方法
 4  */
 5 trait Flyable {
 6   def hasFather = true;
 7   def fly;
 8 }
 9  
10 package com.mtrait
11  
12 /**
13  * @author lucl
14  * 只有一個抽象方法
15  */
16 trait Swimable {
17   def swim;
18 }

  我們定義一種動物,它既會飛也會遊泳,這種動物是魚鷹 FishEagle

 1 /**
 2  * @author lucl
 3  */
 4 class FishEagle extends Animal with Flyable with Swimable {
 5   /**
 6    * 實現抽象類的walk方法
 7    */
 8   override def walk(speed: Int) = {
 9     println ("Fish eagle walk with speed : " + speed + ".");
10   }
11    
12   /**
13    * 實現trait Flyable的方法
14    */
15   override def fly = {
16     println("Fish eagle fly fast.");
17   }
18    
19   /**
20    * 實現trait Swimable的方法
21    */
22   override def swim {
23     println("Fish eagle swim fast.");
24   }
25 }
26  
27 object FishEagle {
28   def main (args : Array[String]) {
29     val fish = new FishEagle;
30     fish.walk(100);
31     fish.fly;
32     fish.swim;
33     println("fish eagle has father ? " + fish.hasFather + ".");
34     // println(fish.swim);    // 輸出為()
35      
36     println();
37     val flyable : Flyable = fish;
38     flyable.fly;
39     
40     val swimable : Swimable = fish;
41     swimable.swim;
42   }
43 }
44  
45 /**
46 輸出結果:
47 Fish eagle walk with speed : 100.
48 Fish eagle fly fast.
49 Fish eagle swim fast.
50 fish eagle has father ? true.
51  
52 Fish eagle fly fast.
53 Fish eagle swim fast.
54 */

  trait很強大,抽象類能做的事情,trait都可以做,它的長處在於可以多繼承。

  trait和抽象類的區別在於抽象類是對一個繼承鏈的,類和類之前確實有父子類的繼承關系,而trait則如其名字,表示一種特征,可以多繼承。

  在對象中混入trait

/**
 * 單獨的日誌模塊
 * 只是標識要記錄日誌,但沒有明確定義如何記錄日誌
 */
trait Logger {
  def log (msg : String) {}
}
 
/**
 * 記錄日誌的具體實現類
 */
trait WriteLogger extends Logger {
  override def log (msg : String) = {println("WriteLogger : " + msg);}
}
 
/**
 * 需要執行的業務操作
 */
trait Action {
  def doAction(action : String);
}
 
class TraitActionImpl extends Action {
  override def doAction(op : String) = println(op);
}
 
class LoggerActionImpl extends Action with Logger {
  override def doAction(op : String) = {
    println(op); 
    // 如果確實需要日誌功能但暫不清楚以何種形式記錄日誌時,可以采用該方法;
    // 當明確了記錄日誌的方式後,再通過如下在對象中混入trait實現。
    log (op);  
  }
}
 
/**
 * @author lucl
 */
object TraitOps {
  def main (args : Array[String]) {
    // 
    println("===================aaaaaa========================");
    // 類本身與記錄日誌Logger沒有關系,但是在對象中混入trait的代碼後,就具備了日誌的功能
    val actionA = new TraitActionImpl with WriteLogger;
    val op = "業務操作";
    actionA.doAction(op);
    actionA.log(op);
     
    //
    println("===================bbbbbb========================");
    // 類實現了Logger,但日誌記錄是空的操作
    val loggerA = new LoggerActionImpl;  
    loggerA.doAction(op);
     
    println("===================cccccc========================");
    // 類實現了Logger,通過在類定義中混入trait實現了自己的記日誌的功能
    val loggerB = new LoggerActionImpl with WriteLogger;
    loggerB.doAction(op);
  }
}
 
/**
輸出結果:
===================aaaaaa========================
業務操作
WriteLogger : 業務操作
===================bbbbbb========================
業務操作
===================cccccc========================
業務操作
WriteLogger : 業務操作
*/

三、總結

  簡單來說,Scala的trait就是類似於Java的接口。使一個類能實現多種功能。

Scala入門2(特質與疊加在一起的特質)