定義
特質(zhì)可以要求混入它的類擴展自另一個類型,但是當使用自身類型(self type)的聲明來定義特質(zhì)時(this: ClassName =>
),這樣的特質(zhì)只能被混入給定類型的子類當中。
如果嘗試將該特質(zhì)混入不符合自身類型所要求的類時,就會報錯。
從技術角度上看,自身類型是在類中提到this時,對于this的假設性類型。從實用角度上看,自身類型指定了對于特質(zhì)能夠混入的具體類的需求。如果你的特質(zhì)僅用于混入另一個或幾個特質(zhì),那么可以指定那些假設性的特質(zhì)。
自身類型在依賴注入的應用
在通過組件構建大型系統(tǒng),而每個組件都有不同的實現(xiàn)的時候,我們需要將組件的不同選擇組裝起來。通常組件之間存在某種依賴關系,比如,數(shù)據(jù)訪問組件可能會依賴日志功能。
每個組件都描述了它所依賴的其他組件的接口,而對實際組件實現(xiàn)的引用是在應用程序被組件起來的時候“注入”的。
對于Scala來說,可以通過特質(zhì)和自身類型達到簡單的依賴注入的效果。
自身類型實現(xiàn)依賴注入
對于日志功能trait Logger {def log(msg: String)}
,它有兩個實現(xiàn):ConsoleLogger
和FileLogger
。
用戶認證特質(zhì)有對日志功能的依賴,用于記錄認證失敗:
trait Auth {
this: Logger =>
def login(id: String, password: String): Boolean
}
應用邏輯依賴于上述兩個特質(zhì),如此定義:
trait App {
this: Logger with Auth =>
...
}
然后我們可以組裝應用,object MyApp extends App with FileLogger("test.log") with MockAuth("users.txt")
。這里將組件黏合成了一個大類型。
蛋糕模式實現(xiàn)組件配置設計
蛋糕模式可以給出更好的設計,對每個服務都提供一個組件特質(zhì)。
組件特質(zhì)包括:
- 任何所依賴的組件,以自身類型表述
- 描述服務接口的特質(zhì)
- 抽象的val,該val將被初始化成服務的一個實例
- 可以有選擇地包含服務接口的實現(xiàn)
trait LoggerComponent {
trait Logger {...}
val logger: Logger
class FileLogger(file: String) extends Logger {...}
...
}
trait AuthComponent {
this: LoggerComponent => //自身類型使得可以訪問日志器
trait Auth {...}
val auth: Auth
class MockAuth(file: String) extends Auth {...}
...
}
這段代碼中,我們使用自身類型表示認證組件對日志器組件的依賴。
通過在程序中進行組件配置可以讓編譯器幫助我們校驗模塊間的依賴關系:
object AppComponents extends LoggerComponent with AuthComponent {
val logger = new FileLogger("test.log")
val auth = new MockAuth("user.txt")
}
轉(zhuǎn)載請注明作者Jason Ding及其出處
jasonding.top
Github博客主頁(http://blog.jasonding.top/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.lxweimin.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354進入我的博客主頁