2014-05-03 46 views
3

我有一個簡單的職業特性,目前實施的情況下,類斯卡拉添加堆疊屬性類

case class Feature(value :String) 

有多個操作裝飾具有不同性質的功能,例如有可能算一個功能然後我可能需要一個CountedFeature函數出現的次數。除了計數,我可能還需要一個WeightedFeature,IndexedFeature等。

我的直覺說,這是適合的特徵,所以我定義了以下特點

trait Counted {def count :Long} 
trait Weighted {def weight :Double} 
trait Indexed {def index :Int} 

兩個問題彈出這個: 1.我需要創建實施特徵的每個組合的具體類(如實施CountedWeightedFeature,CountedIndexedfeature等),還是有一些方法可以避免它。如果我將採取更多的裝飾方式,那麼不可能爲所有組合獲得班級。 2.我想設計一個函數,根據它們的數量來權衡特徵。它的簽名應該是這個樣子:

def computeWeightsByCount(features :List[T <: Feature with Counted]) :List[T with Weighted] = {...} 

牛逼這裏可以被索引或沒有,所以這個功能應該有一些辦法去上課,並instansiate具有堆疊裏面加上原有的類的所有性狀的新類另外一個。

在Scala中有沒有一些優雅的方法可以做到這一點,還是我應該重新考慮這個設計?

回答

0

設計對我來說看起來不錯,但不推薦擴展案例類。原因簡單總結爲什麼可以在這裏找到:https://stackoverflow.com/a/12705634/2186890

所以你可能要重寫Feature因爲這樣的事情:

trait Feature { def value: String } 

現在,你可以定義模式匹配等這樣的情況下,類:

case class CountedFeature(value: String, count: Long) extends Feature with Counted 

有沒有簡單的方法來避免case類這樣的組合爆炸,但你啓動你喜歡的地方使用類型,如Feature with Counted。請記住,您可以輕鬆創建匹配類型Feature with Counted的對象。例如:

val x: Feature with Counted = new Feature with Counted { val value = ""; val count = 0L } 

實施computeWeightsByCount像你想要的是一個有點棘手,因爲沒有簡單的方法來建立一個T with Weighted不知道更多關於T型。但它可以用隱式方法完成。實質上,我們需要有一個定義的路徑,用於從T中爲您想要應用此方法的每個Feature with Counted生成T with Weighted。例如,我們開始與此:

trait Feature { def value: String } 
trait Counted { def count: Long } 
trait Weighted { def weight: Double } 
trait Indexed { def index: Int } 

我們要定義computeWeightsByCount就像你在你的問題做了,但是也考慮採用一個T和重量的隱式方法,併產生一個T with Weighted

def computeWeightsByCount[ 
    T <: Feature with Counted](                      
    features: List[T])(
    implicit weighted: (T, Double) => T with Weighted 
): List[T with Weighted] = { 
    def weight(fc: Feature with Counted): Double = 0.0d 
    features map { f => weighted(f, weight(f)) } 
} 

現在我們需要定義一個隱式方法來根據輸入要素產生加權特徵。我們從Feature with Counted開始獲得Feature with Counted with Weighted。我們會把它放在同伴對象Feature

object Feature { 
    implicit def weight(fc: Feature with Counted, weight: Double): Feature with Counted with Weighted = { 
    case class FCW(value: String, count: Long, weight: Double) extends Feature with Counted with Weighted 
    FCW(fc.value, fc.count, weight) 
    } 
} 

我們可以使用它像這樣:

case class FC(value: String, count: Long) extends Feature with Counted 
val fcs: List[Feature with Counted] = List(FC("0", 0L), FC("1", 1L)) 
val fcws: List[Feature with Counted with Weighted] = computeWeightsByCount[Feature with Counted](fcs) 

對於要計算的加權數的任何類型,你需要定義一個類似這種隱式方法。

無可否認,這遠非一個美麗的解決方案。所以是的,你是對的,你可能想重新考慮設計。然而,這種方法的好處是可以在不需要對computeWeightsByCount進行任何修改的情況下對Feature「層次結構」進一步擴展。無論誰寫新的特質,都可以提供合適的隱含方法。