我們訪問資源需要關注對資源的鎖定、對資源的申請和釋放,還有考慮可能遇到的各種異常。這些事項本身與代碼的邏輯操作無關,但我們不能遺漏。也就是說進入方法時獲取資源,退出方法時釋放資源。這種處理就進入了Execute Around模式的范疇。
在scala里可以用函數值實現這種模式。下面是一個示例,使用Resource類演示了事務的開啟和釋放:
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類的構造器標記為private,這樣就只能在Resource類內部和它的伴生類中創建實例了。因為只能在這兩個地方創建實例,從而保證是可以按照確定的方式使用這個類的對象了,也就可以保證其行為是按照確定的方式執行。cleanUp()方法也被標記為private,確保不會被意外調用。第一行的print語句是具體事務操作的占位符。調用構造函數時,事務啟動;調用cleanUp()函數時,事務終結。此外Resource類中還準備了一些實例方法,如op1()、op2()等。
在伴生對象里有一個默認public的方法use,它接收一個函數值作為參數。use()方法創建了一個Resource的實例,在try和finally塊的保護之下,把這個實例傳給了給定的函數值。在finally塊里,調用了Resource私有實例方法cleanUp()。
看一下是如何使用Resource類的:
Resource.use { resource =>resource.op1resource.op2resource.op3resource.op1
}
代碼輸出結果是:
調用Resource的伴生對象時,會自動創建一個Resource實例,等到傳遞的函數值執行結束后,會自動調用cleanUp方法釋放占用的資源。
上面模式的一個變體是Loan模式。如果想確保非內存資源得到確定性釋放,就可以使用這個模式。可以這樣認為這種資源密集型的對象是借給你的,用過之后應該立即歸還。
下面是一個Loan模式的例子:
import java.io._def writeToFile(fileName: String)(codeBlock: PrintWriter => Unit) = {val writer = new PrintWriter(new File(fileName))try {codeBlock(writer)} finally {writer.close()} }
現在調用writeToFile()將一些內容寫入文件:
writeToFile("output.txt") { writer => writer write "hello from Scala" }
方法的執行結果:
作為writeToFile()方法的使用者,我們不必操心文件的關閉。在代碼塊里,這個文件是借給我們用的。我們可以用得到的PrintWriter實例進行寫操作,一旦從這個塊返回,方法就會自動關閉文件。
###############