天天看點

Scala:初識貸出模式(Loan Pettern)

  再一次讀到 Scala 中的“貸出模式(Loan Pattern)”這個術語,這才比上次稍了解一些。我的了解,此一模式大概是說,對于那些資源密集(resource-intensive)型對象的使用應該使用這一模式。

使用這一模式的原因是,既然資源集中在一個對象中,那麼使用者代碼就不能一直保持着獲得的所有資源,而應該在需要時就向資源供給方進行借貸,使用完畢之後立即歸還。

此外,Scala 中将函數也是對象,可以像參數那樣傳遞給另一個函數的特征使得貸出模式更加有意義。客戶代碼借貸了所需的資源,接下來如何使用這些資源以完成特定的任務則由客戶決定。就像我們向銀行貸款,這些錢的具體用途是客戶決定,也是客戶才明确的。

對于此類資源,有資料庫連接配接、IO操作等,這些是我們用完則務必立即釋放的資源。而且,資源使用完畢業意味着将被自動回收,我們不必操心資源回收的過程。

下面是一個 Scala 腳本代碼,客戶提供一個檔案名,利用writeFile 方法中能夠一個向該檔案寫入内容的 PrintWriter 對象。而具體如何使用這個 PrintWriter 對象則由使用者确定,使用完則由自動釋放。  

def writeFile(fileName: File)(operation: PrintWriter => Unit) { 

    val writer = new PrintWriter(fileName)  // 貸出資源writer 

    try{ 

        operation(pw)   // 客戶使用資源 

    }finally { 

        writer.close()  // 用完則釋放被回收 

    } 

上面 writeFile 方法的定義使用到了 Scala 中的curring技巧,是以才會看到 writeFile 定義之後有兩個參數清單(即兩個小括号對),後面的參數 operation 用于傳入客戶具體想要的操作(即怎麼使用資源)。 

客戶代碼如下: 

val file = new File("test.txt") 

writeFile(file) { 

    // 使用資源的具體操作 

    writer => writer.println("haolloyin ...\r\n" + 

new java.util.Date()) 

執行該腳本,會發現在目前目錄下生成一個 test.txt 檔案,裡面的内容如下:

haolloyin... 

Fri Sep 03 22:44:18 CST 2010 

在這個例子中,客戶對資源的使用完全是自定義的,如上面的writer => writer.println(…) 所示。但是有時候我們會遇到一些本身已經預定義好所具備操作的資源,那麼此時可以結合 Singleton Object 單例對象的使用特點對其伴生類所代表的資源進行建立和使用。  

同時使用資源類與其單例對象的用意在于,確定該資源隻能通過伴生對象進行合法通路,控制好資源的客戶源的合法性。這在《Scala 鉛筆書》中有下面這個例子,我把代碼拷貝并注釋如下:

// 主構造器私有,限制其對象(資源)的建立範圍 

class Resource private() { 

  println("Starting transaction...")    // 被作為主構造器的語句而執行 

  // 資源的收回也是内部處理 

  private def cleanUp() { println("Ending transaction...") } 

  // 資源類本身預定義的具體操作 

  def op1 = println("Operation 1")  

  def op2 = println("Operation 2") 

  def op3 = println("Operation 3") 

// 單例對象,客戶使用資源的入口 

object Resource { 

  def use(codeBlock: Resource => Unit) { 

    val resource = new Resource  // 貸出資源 

    try { 

      codeBlock(resource)    // 使用資源 

    finally { 

      resource.cleanUp()    // 資源被回收 

  } 

客戶代碼如此使用資源:  

Resource.use { resource => 

  resource.op1 

  resource.op2 

  resource.op3 

  resource.op1 // 任意的操作調用序列 

    程式輸出:

Starting transaction... 

Operation 1 

Operation 2 

Operation 3 

Ending transaction... 

本文轉自 xxxx66yyyy 51CTO部落格,原文連結:http://blog.51cto.com/haolloyin/387138,如需轉載請自行聯系原作者