我有一个简单的类功能,目前作为案例类实现
case class Feature(value :String)
有多个操作装饰具有不同属性的特征,例如,有一个函数可以计算特征的出现次数,因此我可能需要一个CountedFeature。除了计数,我可能还需要WeightedFeature,IndexedFeature等等。
我的直觉说它适合于特征所以我定义了以下特征
trait Counted {def count :Long}
trait Weighted {def weight :Double}
trait Indexed {def index :Int}
弹出两个问题: 1.我是否需要创建一个实现每个特征组合的具体类(e.x.实现CountedWeightedFeature,CountedIndexedfeature等),或者有一些方法可以避免它。如果我要转向更多的装饰品,就不可能为所有组合保留课程。 2.我想设计一个根据计数对功能进行加权的功能。它的签名应该类似于:
def computeWeightsByCount(features :List[T <: Feature with Counted]) :List[T with Weighted] = {...}
这里可能是索引与否,所以这个函数应该有一些方法来获取一个类并实现一个新类,它具有堆叠在内部的原始类的所有特征以及另外一个。
在Scala中有一些优雅的方法可以做到这一点,还是我应该重新考虑这个设计?
答案 0 :(得分: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 with Weighted
从T
生成Feature with Counted
。例如,我们从这开始:
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 with Weighted
获取Feature with Counted
。我们将其放在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
&#34;层次结构的任何进一步扩展&#34;可以在不需要对computeWeightsByCount
进行任何更改的情况下制作。编写新特征的人也可以提供适当的隐式方法。