2009-08-24 71 views
4

我經常遇到想要向不受控制的類添加其他方法的問題。例如,我可能希望有一個功能prettyPrint,它可以在不具有統一api的不同對象類型上運行(例如,特殊的__str__方法)。Scala或Jython中多方法的替代方案

Nice語言和R使用multimethods完成此操作,這很好地避免了訪問者模式。例如,R具有plot()功能。單個程序員可以創建新的類來定義數據類型(例如,網絡圖或股票行情數據)。然後,二級用戶/程序員可以編寫一個繪圖函數來填寫該功能,即使他們無法訪問圖形或股票代碼或其他繪圖函數的代碼。

鑑於我想稍後添加大量功能,使用class.method()似乎不可行。很多class_plot()函數爲每個類型也似乎是一個壞主意。定義一個大的plot()函數檢查類型是不可擴展的。

什麼是multimethods的替代方法?特別是,我對可能在Jython和Scala中工作的設計感興趣。

回答

7

的方法添加到類在Scala中最簡單的方法:

implicit def defSum(l: List[Double]): Double = new AnyRef { def sum = l.foldLeft(0.0)(_ + _) } 

或者,在斯卡拉2.8,用一種方法處理數字的特殊情況下,

implicit def defSum[T](l: List[T])(implicit n: Numeric[T]) = new AnyRef { 
    import n.mkNumericOps 
    def sum = l.foldLeft(n.zero)(_ + _) 
} 

只有這ISN」在Scala 2.8上需要,因爲它已經定義了sum

您也可以實例化時添加的特徵:

// Immutable class 
case class Point(x: Int, y: Int) 

// Somewhere else in the code  
trait MyPlot { 
    self: Point => 
    import self._ 

    def plot = println("At "+x+", "+y) 
} 

// Usage 
val p = new Point(1,2) with MyPlot 
p.plot 

什麼你不能做的是動態添加的方法(即,在運行時間,而不是編譯時)的對象。在第一種情況下,你在說「將這種方法添加到這個類中」。在第二種情況下,你說「用這個特性創建這個對象」。這些都沒問題,但「添加此方法到這個對象」不是。

1

的Python和Jython允許混入類,這樣你就可以使用它們來保持你的「擴展」的方法:

class Derived(Base, Mixin1, Mixin2, ...): 
    ... 

顯然,如果你想要的plot方法對不同類型的主機,那麼你需要有實現的地方 - 這可能導致多個mixin類。另一種方法是使用字典,其中鍵是類型,值是函數(或函數集):請參見this answer

我還假設你不想猴子補丁類,這也是技術上可行的(儘管不是可取的)。