整体设计在我看来很好,除了不建议扩展 case class。可以在https://dev59.com/Cmcs5IYBdhLWcg3wmlWk#12705634中找到关于此事的简要原因。
因此,您可能需要将 Feature
重写为以下内容:
trait Feature { def value: String }
现在你可以像这样为模式匹配等定义 case classes:
case class CountedFeature(value: String, count: Long) extends Feature with Counted
避免像这样的 case classes 的组合爆炸并不容易,但是您可以随时使用 Feature with Counted
等类型。请记住,您可以轻松地创建与类型 Feature with Counted
匹配的对象。例如:
val x: Feature with Counted = new Feature with Counted { val value = ""; val count = 0L }
实现像你想要的computeWeightsByCount
有点棘手,因为没有简单的方法来构建一个带有权重的T
,除非我们更多地了解类型T
。但是可以通过隐式方法完成。基本上,我们需要为每个你想要应用此方法的Feature with Counted
定义生成T with Weighted
的路径从T
开始。例如,我们从这里开始:
trait Feature { def value: String }
trait Counted { def count: Long }
trait Weighted { def weight: Double }
trait Indexed { def index: Int }
我们想要像您在问题中所做的那样定义
computeWeightsByCount
,但同时还采用一个隐式方法,该方法接受一个
T
和一个权重,并生成一个带有权重的
T
:
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
开始,这个
Feature
是从一个带有计数的
Feature
中得到的。我们将把它放在
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)
对于任何想要计算加权计数的类型,您需要定义类似的隐式方法。
诚然,这远非完美的解决方案。所以,是的,您说得对,您可能需要重新考虑设计。然而,这种方法的优点在于,进一步扩展Feature
“层次结构”的任何后续扩展都可以进行,而无需对computeWeightsByCount
进行任何更改。编写新特性的人也可以提供相应的隐式方法。