面向?qū)ο蟮木幊?/h1>

2018-02-24 15:49 更新

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

依賴注入不妨礙使用公共接口,或在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)類型。結(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()
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)