Scala的單例對象
Scala不能定義靜態(tài)成員,而是代之定義單例對象(singleton object)。以object關(guān)鍵字定義。
對象定義了某個類的單個實例,包含了你想要的特性:
object Accounts{
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
}
當你在應(yīng)用程序中需要一個新的唯一賬號時,調(diào)用Account.newUniqueNumber()即可。
對象的構(gòu)造器在該對象第一次被使用時調(diào)用。
在下面幾個場景下可以使用Scala單例對象:
- 作為存放工具函數(shù)或常量的地方
- 高效地共享單個不可變實例
- 需要使用單個實例來協(xié)調(diào)某個服務(wù)時
類和單例對象間的差別是,單例對象不帶參數(shù),而類可以。因為單例對象不是用new關(guān)鍵字實例化的,所以沒機會傳遞給它實例化參數(shù)。每個單例對象都被實現(xiàn)為虛擬類(synthetic class)的實例,并指向靜態(tài)的變量,因為它們與Java靜態(tài)類有相同的初始化語義。
獨立對象(standalone object)
不與伴生類共享名稱的單例對象稱為獨立對象。它可以用在很多地方,例如作為相關(guān)功能方法的工具類,或者定義Scala應(yīng)用的入口點。
伴生對象(companion object)
當單例對象與某個類共享同一個名稱時,它就被稱為是這個類的伴生對象(companion object)。類和它的伴生對象必須定義在同一個源文件中。類被稱為是這個單例對象的伴生類(companion class)。類和它的伴生對象可以互相訪問其私有成員。
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double){ balance += amount }
...
}
object Account { //伴生對象
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
}
注意:
- 類的伴生對象可以被訪問,但并不在作用域當中。Account類必須通過Account.newUniqueNumber()來調(diào)用伴生對象的方法。
- 在REPL中,要同時定義類和對象,必須用粘貼模式。鍵入
:paste
,然后鍵入或粘貼類和對象的定義,最后一Ctrl+D退出粘貼模式。
將伴生對象作為工廠使用
我們通常將伴生對象作為工廠使用。
下面是一個簡單的例子,可以不需要使用’new’來創(chuàng)建一個實例了。
class Bar(foo: String)
object Bar {
def apply(foo: String) = new Bar(foo)
}
繼承自類和特質(zhì)的單例對象
一個object可以擴展類以及一個或多個特質(zhì),其結(jié)果是一個擴展了指定類以及特質(zhì)的類的對象,同時擁有在對象定義中給出的所有特性。
繼承自抽象類的例子
擴展類的一個有用的使用場景是給出可被共享的缺省對象。舉例來說,考慮在程序中引入一個可撤銷動作的類:
abstract class UndoableAction(val description: Sting) {
def undo(): Unit
def redo(): Unit
}
object DoNothingAction extends UndoableAction("Do nothing") {
override def undo() {}
override def redo() {}
}
//打開和保存功能尚未實現(xiàn)
val action = Map("open" -> DoNothingAction, "save" -> DoNothingAction, ...)
DoNothingAction對象可以被所有需要這個缺省行為的地方共用
混入特質(zhì)的例子
有時,你可以混入像debugger或logging之類的特質(zhì)來構(gòu)建對象幫助調(diào)試對象,這樣使得構(gòu)建的對象實例具有l(wèi)og之類的方法:
trait Debugger {
def log(message: String){
//do something with message
}
}
//no debugger
val child = new Child
//debugger added as the object is created
val problemChild = new ProblemChild with Debugger
轉(zhuǎn)載請注明作者Jason Ding及其出處
GitCafe博客主頁(http://jasonding1354.gitcafe.io/)
Github博客主頁(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.lxweimin.com/users/2bd9b48f6ea8/latest_articles)
百度搜索jasonding1354進入我的博客主頁