標籤:大資料 scala
大資料Scala編程.問題集(02)
by 高煥堂
洞庭國際智能硬體檢測基地 & 中雲大資料中心(IDC) 首席架構師
微博:@高煥堂_台北
Q-02: Scala語言的trait具有什麼設計涵意?
Answer:
大家都知道介面(Interface)的概念,也知道一個類(Class)或一個模組(Module)能實現多個介面。就像一個房間可以有多個門,或一座四合院可以有多個門口一樣。如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/56/C3/wKiom1SM0p7gRO4uAADKRTiSOPE682.jpg" title="qq02_01.png" alt="wKiom1SM0p7gRO4uAADKRTiSOPE682.jpg" />
將四合院的概念對應到軟體上,一個軟體的類可以實踐多個介面,如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C0/wKioL1SM03vygOLMAABQoRJ-gwg376.jpg" title="qq02_02.png" alt="wKioL1SM03vygOLMAABQoRJ-gwg376.jpg" />
現在,先拿一個類和一個介面的設計架構來看看,如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C3/wKiom1SM0wfTSFiDAAB3es6DqvE969.jpg" title="qq02_03.png" alt="wKiom1SM0wfTSFiDAAB3es6DqvE969.jpg" />
在一般軟體設計上,介面(Interface)意味著:它就是一個純粹抽象類別(Pure abstract class)。也就是說,它內含一個或多個抽象函數(Abstract function),而且是公用(Public)的函數。Gamma等人在其所著 Design Patterns書裡主張:
"Program to an interface, not an implementation."
(針對介面而寫編程,不要針對實現。)
這意味了,通常架構師(團隊)會先設計好介面,然後工程師(團隊)再依循介面的定義而開發實現代碼。於是,架構師團隊與工程師團隊,兩個團隊之間是相互分工合作(Collaboration)的。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/56/C3/wKiom1SM07fDBp1kAACtkx2mgkc079.jpg" title="qq02_04.png" alt="wKiom1SM07fDBp1kAACtkx2mgkc079.jpg" />
由於架構師團隊裡,也常常含有開發人員(或架構師兼工程師),因而也常常會去寫一些代碼,來實現介面裡的抽象函數,提供一些介面的預設行為(Default behavior)。此時,所設計的架構會變成為:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/56/C0/wKioL1SM1H7Q4pq7AACgbQqvf8Q770.jpg" title="qq02_05.png" alt="wKioL1SM1H7Q4pq7AACgbQqvf8Q770.jpg" />
將裡的IA介面和IA_impl類,看成一個整體,特別稱之為特性(Trait),如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/56/C3/wKiom1SM1AOC513MAACQJYBn4G4923.jpg" title="qq02_06.png" alt="wKiom1SM1AOC513MAACQJYBn4G4923.jpg" />
以上是從架構設計的角度來思考的,若對應到Scala代碼,可表示如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C0/wKioL1SM1QGDAigvAABmpLyvYGc967.jpg" title="qq02_07.png" alt="wKioL1SM1QGDAigvAABmpLyvYGc967.jpg" />
// trait的定義
trait TA {
def transact(){ //預設行為代碼
onTransact // 調用抽象函數
}
def onTransact // 抽象函數
}
// class的定義
class EVAPlane extends TA {
var manufacturer : String = ""
var capacity : Int = 0
var mfr_date : String = ""
def pr_capacity {
println(capacity)
}
def onTransact {
println("this is onTransact.")
}
}
// myApp
object myApp {
def main( args: Array[String] ) {
val p1 = new EVAPlane
val p2 = new EVAPlane
p1.transact
p2.transact
}
由於Scala代碼編譯(Compile)時,會轉換成為JVM引擎可執行檔ByeCode,其受限於JVM引擎的單繼承(Single inheritance)的限制。在Scala語言裡,無法實踐架構師的多重介面及其預設行為的架構設計,如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C3/wKiom1SM1ITxLAsHAACrUHzklZU110.jpg" title="qq02_08.png" alt="wKiom1SM1ITxLAsHAACrUHzklZU110.jpg" />
但是,卻能善用Scala的Trait來實踐之,如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/56/C3/wKiom1SM1TPQkAmfAACLI5AenS8168.jpg" title="qq02_09.png" alt="wKiom1SM1TPQkAmfAACLI5AenS8168.jpg" />
Scala借重JVM引擎的多重介面實現(Implement)機制,以及對象委託(Delegation)機制來實踐的trait extends機制;而不是依賴 JVM引擎原有的class extends機制。如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/56/C0/wKioL1SM1fiyKBBRAACv6Yisetw082.jpg" title="qq02_10.png" alt="wKioL1SM1fiyKBBRAACv6Yisetw082.jpg" />
運用了JVM引擎層級的Implement和Delegation機制來實踐Scala原始碼層級的trait extends機制。如:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C0/wKioL1SM1kjzFhMVAACyCdZKLbg560.jpg" title="qq02_11.png" alt="wKioL1SM1kjzFhMVAACyCdZKLbg560.jpg" />
這樣,一方面架構師團隊可以定義其介面(Interface),例如設計出裡的IA和IB,並撰寫其介面的預設行為(Default behavior)代碼,如裡的IA_impl和IB_impl類,並以Scala的trait形式表達出來。
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/56/C3/wKiom1SM1dziAlMhAADRJ-iW_l0892.jpg" title="qq02_12.png" alt="wKiom1SM1dziAlMhAADRJ-iW_l0892.jpg" />
然後,將該trait交給工程師團隊去撰寫EVAPlane類或其子類的實現代碼。達成了架構師團隊與工程師團隊的美好分工合作了;也實踐了 "Program to an interface, not an implementation."(針對介面而寫編程,不要針對實現。)的設計原則。
請繼續學習:高老師的相關視頻
相關文章:大資料Scala編程問題集(01)
~ end ~
大資料Scala編程.問題集(02)