這個名字不知道取得是否合適,簡單來講要乾的事情就是給某個類型添加一些擴展方法,此場景在各類語言中都會用到,好比 C# 語言,若是咱們使用一個別人寫好的類庫,而又想給某個類庫添加一些本身封裝的方法,最好的方式就是使用擴展方法,具體實現方式此處不贅述。scala
起初,我覺得在 Scala 中也是這樣使用的,可是直到今天我才恍然大悟,在 Scala 中擴展方法其實不是那麼簡單,此處說的不簡單主要說的是實現的意義不簡單,而不是實現方法。本文對此進行簡單介紹。code
首先,來講明實現方法,正如上文所說,在 Scala 中其實實現起來也很容易。對象
首先咱們有一個要擴展的類型假定爲 C,定義以下:繼承
trait A { def play = println("play") }
就是這麼簡單的一個類,包含一個 play 方法,固然能夠有各類各樣的子類繼承於他,及包含其餘方法。ci
第二步,定義一個擴展方法的類型:it
trait BB[+T] { def self: T }
此類用於包裝咱們的被擴展類型,其中 self 就是一個要擴展類型的實例。(此處名字取 BB 實非本意,不知是 scala bug 仍是其餘問題,若是此處只使用 B 來命名,下面會報錯,有知情者煩請指點一二。)class
第三步,定義一個 trait 繼承自 BB:擴展
trait C extends BB[A] { def draw = self.play }
此類型裏能夠定義一系列的方法,這些方法就是即將被擴展的方法,咱們能夠直接使用 self 來表示被擴展的對象實例,能夠直接調用他的方法。coding
第四步,實現一個隱式類型,將 A 對象隱式轉換爲 C:bug
implicit class D(val self: A) extends C
最終,咱們能夠直接對 A 對象的實例調用擴展方法:
new A {}.draw
思路縝密,邏輯清晰((*^_^*)),實現起來很容易。開始的時候我覺得就是這樣,因此爲每一個類型寫了一堆的擴展方法,自我感受良好,調用起來很方便。
可是這個地方有個問題,既然咱們本身定義了類型A,爲何不直接將 draw 方法也寫到這裏面呢,瞎折騰啥,我以前是這麼想的,也是這麼用的。然而,今天我忽然意識到一個問題,在我使用的一個類庫中,不少本身定義的類型也採用此種方式定義了大量的擴展方法,那我就納悶了,爲何不直接寫到類型的定義中呢?
沉思半天,我恍然大悟,這是一種良好的封裝方法。簡單說來就是 A 這個類型可能包含了大量的不一樣種類的方法,好比對於地理信息系統來講,一個瓦片能夠包含投影、裁剪、切割等多種種類的方法,每一個種類可能包含了一系列方法,因此採用這種方式的好處就是能夠將這些不一樣種類的方法放到不一樣的擴展類型中進行管理,實現良好的封裝。而且在後續調用中,無需判斷此對象是不是 A 對象,只要判斷此對象是不是 C 對象便可直接調用 C 中的方法,這樣就對功能實現了良好的劃分。
看似一個簡單的擴展方法,也有如此多的深層次邏輯,仍是須要學會思考、深刻的思考,這樣才能發現更多 coding 中美的地方。