在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Scala/ Trait 用來實現(xiàn)可疊加的修改操作
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實現(xiàn)方法
try 表達式處理異常
選擇瘦接口還是胖接口設計?
組合和繼承–小結
創(chuàng)建新的控制結構
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調用基類構造函數(shù)
減低代碼重復
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴展類
函數(shù)–部分應用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實現(xiàn)可疊加的修改操作

Trait 用來實現(xiàn)可疊加的修改操作

我們已經看到 Trait 的一個主要用法,將一個瘦接口變成胖接口,本篇我們介紹 Trait 的另外一個重要用法,為類添加一些可以疊加的修改操作。Trait 能夠修改類的方法,并且能夠通過疊加這些操作(不同組合)修改類的方法。

我們來看這樣一個例子,修改一個整數(shù)隊列,這個隊列有兩個方法:put 為隊列添加一個元素,get 從隊列讀取一個元素。隊列是先進先出,因此 get 讀取的順序和 put 的順序是一致的。

對于上面的隊列,我們定義如下三個 Trait 類型:

  • Doubling : 隊列中所有元素X2。
  • Incrementing: 隊列中所有元素遞增。
  • Filtering: 過濾到隊列中所有負數(shù)。

這三個 Trait 代表了修改操作,因為它們可以用來修改隊列類對象,而不是為隊列類定義所有可能的操作。這三個操作是可以疊加的,也就是說,你可以通過這三個基本操作的任意不同組合和原始的隊列類“混合”,從而可以得到你所需要的新的隊列類的修改操作。

為了實現(xiàn)這個整數(shù)隊列,我們可以定義這個整數(shù)隊列的一個基本實現(xiàn)如下:

import scala.collection.mutable.ArrayBuffer
abstract class IntQueue {
  def get():Int
  def put(x:Int)
}
class BasicIntQueue extends IntQueue{
  private val buf =new ArrayBuffer[Int]
  def get()= buf.remove(0)
  def put(x:Int) { buf += x }
}

下面我們可以使用這個實現(xiàn),來完成隊列的一些基本操作:

scala> val queue = new BasicIntQueue
queue: BasicIntQueue = BasicIntQueue@60d134d3
scala> queue.put (10)
scala> queue.put(20)
scala> queue.get()
res2: Int = 10
scala> queue.get()
res3: Int = 20

這個實現(xiàn)完成了對象的基本操作,看起來了還可以,但如果此時有新的需求,希望在添加元素時,添加元素的雙倍,并且過濾掉負數(shù),你可以直接修改 put 方法 來完成,但之后需求又變了,添加元素時,添加的為參數(shù)的遞增值,你也可以修改 put 方法,這樣顯得隊列的實現(xiàn)不夠靈活。

我們來看看如果使用 Trait 會有什么結果,我們實現(xiàn) Doubling,Incrementing,F(xiàn)iltering 如下:

trait Doubling extends IntQueue{
  abstract override def put(x:Int) { super.put(2*x)}
}
trait Incrementing extends IntQueue{
  abstract override def put(x:Int) { super.put(x+1)}
}
trait Filtering extends IntQueue{
  abstract override def put (x:Int){
    if(x>=0) super.put(x)
  }
}

我們可以看到所有的 Trait 實現(xiàn)都已 IntQueue 為基類,這保證這些 Trait 只能和同樣繼承了 IntQueue 的類“混合”,比如和 BasicIntQueue 混合,而不可以和比如前面定義的 Rational 類混合。

此外 Trait 的 put 方法中使用了 super,通常情況下對于普通的類這種調用是不合法的,但對于 trait來說,這種方法是可行的,這是因為 trait 中的 super 調用是動態(tài)綁定的,只要和這個 Trait 混合在其他類或 Trait 之后,而這個其它類或 Trait 定義了 super 調用的方法即可。這種方法是實現(xiàn)可以疊加的修改操作是必須的,并且注意使用 abstract override 修飾符,這種使用方法僅限于 Trait 而不能用作 Class 的定義上。

有了這三個 Trait 的定義,我們可以非常靈活的組合這些 Trait 來修改 BasicIntQueue 的操作。

首先我們使用 Doubling Trait

scala> val queue = new BasicIntQueue with Doubling
queue: BasicIntQueue with Doubling = $anon$1@3b004676
scala> queue.put(10)
scala> queue.get()
res1: Int = 20

這里通過 BasicIntQueue 和 Doubling 混合,我們構成了一個新的隊列類型,每次添加的都是參數(shù)的倍增。

我們在使用 BasicIntQueue 同時和 Doubling 和 Increment 混合,注意我們構造兩個不同的整數(shù)隊列,不同時 Doubling 和 Increment 的混合的順序

scala> val queue1 = new BasicIntQueue with Doubling with Incrementing
queue1: BasicIntQueue with Doubling with Incrementing = $anon$1@35849932
scala> val queue2 = new BasicIntQueue with Incrementing  with Doubling
queue2: BasicIntQueue with Incrementing with Doubling = $anon$1@4a4cdea2
scala> queue1.put(10)
scala> queue1.get()
res4: Int = 22
scala> queue2.put(10)
scala> queue2.get()
res6: Int = 21

可以看到結果和 Trait 混合的順序有關,簡單的說,越后混合的 Trait 作用越大。因此 queue1 先+1,然后 X2,而 queue 先 X2 后+1。

最后我們看看三個 Trait 混合的一個例子:

scala> val queue = new BasicIntQueue with Doubling with Incrementing with Filtering
queue: BasicIntQueue with Doubling with Incrementing with Filtering = $anon$1@73a4eb2d
scala> queue.put(10)
scala> queue.put(-4)
scala> queue.put(20)
scala> queue.get()
res10: Int = 22
scala> queue.get()
res11: Int = 42
scala> queue.get()
java.lang.IndexOutOfBoundsException: 0
        at scala.collection.mutable.ResizableArray$class.apply(ResizableArray.scala:44)
        at scala.collection.mutable.ArrayBuffer.apply(ArrayBuffer.scala:44)
        at scala.collection.mutable.ArrayBuffer.remove(ArrayBuffer.scala:163)
        at BasicIntQueue.get(<console>:11)
        at .<init>(<console>:15)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
        at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
        at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
        at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
        at java.lang.Thread.run(Thread.java:744)

最后的異常時因為隊列為空(過濾掉了負數(shù)),我們沒有添加錯誤處理,元素 -4 沒有被添加到了隊列中。

由此可以看出,通過 Trait 可以提高類的實現(xiàn)的靈活性,你可以通過這些 Trait 的不同組合定義了多種不同的對列類型。