面向對象的編程

2018-02-24 15:49 更新

Scala的博大很大程度上在于它的對象系統。Scala中所有的值都是對象,就這一意義而言Scala是門純粹的語言;基本類型和組合類型沒有區(qū)別。Scala也提供了mixin的特性允許更多正交地、細粒度地構造一些在編譯時受益于靜態(tài)類型檢測的可被靈活組裝的模塊。

mixin系統的背后動機之一是消除傳統的依賴注入。這種“組件風格(component style)”編程的高潮是是the cake pattern.

依賴注入

在我們的使用中,我們發(fā)現Scala本身刪除了很多經典(構造函數)依賴注入的語法開銷,我們更愿意就這樣用: 它更清晰,依賴仍然植根于(構造)類型,而類構造語法是如此微不足道而變得輕而易舉。有些無聊,簡單,但有效。對模塊化編程時使用依賴注入,特別是,組合優(yō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 }
 }

這是常見的注入工廠?— 用于產生其他對象的對象。在這些例子中,更青睞用簡單的函數而非專有的工廠類型。

 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應該限制,這樣用戶不會無意中依賴實現細節(jié)并限制了作者修改它們的能力: 它們對于好的模塊化設計是至關重要的。一般來說,擴展公開APIs比收縮公開的APIs容易的多。差勁的注釋(annotation)也能危害到你代碼向后的二進制兼容性。(譯注:comments和annotation都可翻譯成注釋,但意義不同。annotation在Java和Scala有特定的含義)

private[this]

一個類的成員標記為私有的,

 private val x: Int = ...

它對這個類的所有實例來說都是可見的(但對其子類不可見)。大多情況,你想要的是 private[this] 。

 private[this] val: Int = ..

這個修飾限制了它只對當前特定的實例可見。Scala編譯器會把private[this]翻譯為一個簡單的字段訪問(因為訪問僅限于靜態(tài)定義的類),這樣有時有助于性能優(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()方法的調用者會看到以返回實例(Foo with Bar)的受限視圖。

結構類型

不要在正常情況下使用結構類型。結構類型有著便利且強大的特性,但不幸的是在JVM上的實現不是很高效。 然而——由于實現的怪癖——它提對執(zhí)行反射(reflection)供了很好的簡寫形式。

 val obj: AnyRef
 obj.asInstanceOf[{def close()}].close()
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號