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