Scala的博大很大程度上在于它的對(duì)象系統(tǒng)。Scala中所有的值都是對(duì)象,就這一意義而言Scala是門純粹的語言;基本類型和組合類型沒有區(qū)別。Scala也提供了mixin的特性允許更多正交地、細(xì)粒度地構(gòu)造一些在編譯時(shí)受益于靜態(tài)類型檢測(cè)的可被靈活組裝的模塊。
mixin系統(tǒng)的背后動(dòng)機(jī)之一是消除傳統(tǒng)的依賴注入。這種“組件風(fēng)格(component style)”編程的高潮是是the cake pattern.
在我們的使用中,我們發(fā)現(xiàn)Scala本身刪除了很多經(jīng)典(構(gòu)造函數(shù))依賴注入的語法開銷,我們更愿意就這樣用: 它更清晰,依賴仍然植根于(構(gòu)造)類型,而類構(gòu)造語法是如此微不足道而變得輕而易舉。有些無聊,簡(jiǎn)單,但有效。對(duì)模塊化編程時(shí)使用依賴注入,特別是,組合優(yōu)于繼承—這使得程序更加模塊化和可測(cè)試的。當(dāng)遇到需要繼承的情況,問問自己:在語言缺乏對(duì)繼承支持的情況下如何構(gòu)造程序?答案可能是令人信服的。
依賴注入典型的使用到 trait (譯注:可以理解為和Java中Interface相似)
trait TweetStream {
def subscribe(f: Tweet => Unit)
}
class HosebirdStream extends TweetStream ...
class FileStream extends TweetStream ..
class TweetCounter(stream: TweetStream) {
stream.subscribe { tweet => count += 1 }
}
這是常見的注入工廠?— 用于產(chǎn)生其他對(duì)象的對(duì)象。在這些例子中,更青睞用簡(jiǎn)單的函數(shù)而非專有的工廠類型。
class FilteredTweetCounter(mkStream: Filter => TweetStream) {
mkStream(PublicTweets).subscribe { tweet => publicCount += 1 }
mkStream(DMs).subscribe { tweet => dmCount += 1 }
}
依賴注入不妨礙使用公共接口,或在trait中實(shí)現(xiàn)公共代碼。恰恰相反—正是因?yàn)橐韵略蚨叨裙膭?lì)使用trait:一個(gè)具體的類可以實(shí)現(xiàn)多接口(traits),公共的代碼可以通過這些類復(fù)用。
保持traits簡(jiǎn)短并且是正交的:不要把分離的功能混在一個(gè)trait里,考慮將最小的相關(guān)的意圖放在一起。例如,想象一下你要做一些IO的操作:
trait IOer {
def write(bytes: Array[Byte])
def read(n: Int): Array[Byte]
}
分離兩個(gè)行為:
trait Reader {
def read(n: Int): Array[Byte]
}
trait Writer {
def write(bytes: Array[Byte])
}
可以將它們以混入(mix)的方式實(shí)現(xiàn)一個(gè)IOer : new Reader with Writer...接口最小化促使更好的正交性和更清晰的模塊化。
Scala有很豐富的可見性修飾。使用這些可見性修飾很重要,因?yàn)樗鼈兌x了哪些構(gòu)成公開API。公開APIs應(yīng)該限制,這樣用戶不會(huì)無意中依賴實(shí)現(xiàn)細(xì)節(jié)并限制了作者修改它們的能力: 它們對(duì)于好的模塊化設(shè)計(jì)是至關(guān)重要的。一般來說,擴(kuò)展公開APIs比收縮公開的APIs容易的多。差勁的注釋(annotation)也能危害到你代碼向后的二進(jìn)制兼容性。(譯注:comments和annotation都可翻譯成注釋,但意義不同。annotation在Java和Scala有特定的含義)
private[this]
一個(gè)類的成員標(biāo)記為私有的,
private val x: Int = ...
它對(duì)這個(gè)類的所有實(shí)例來說都是可見的(但對(duì)其子類不可見)。大多情況,你想要的是 private[this] 。
private[this] val: Int = ..
這個(gè)修飾限制了它只對(duì)當(dāng)前特定的實(shí)例可見。Scala編譯器會(huì)把private[this]翻譯為一個(gè)簡(jiǎn)單的字段訪問(因?yàn)樵L問僅限于靜態(tài)定義的類),這樣有時(shí)有助于性能優(yōu)化。
在Scala中創(chuàng)建單例類型是很常見的,例如:
def foo() = new Foo with Bar with Baz {
...
}
在這種情況下,可以通過聲明返回類型來限制可見性:
def foo(): Foo with Bar = new Foo with Bar with Baz {
...
}
foo()方法的調(diào)用者會(huì)看到以返回實(shí)例(Foo with Bar)的受限視圖。
不要在正常情況下使用結(jié)構(gòu)類型。結(jié)構(gòu)類型有著便利且強(qiáng)大的特性,但不幸的是在JVM上的實(shí)現(xiàn)不是很高效。 然而——由于實(shí)現(xiàn)的怪癖——它提對(duì)執(zhí)行反射(reflection)供了很好的簡(jiǎn)寫形式。
val obj: AnyRef
obj.asInstanceOf[{def close()}].close()
更多建議: