有多种方法可以对 Scala 中所需的抽象进行建模。我将首先描述最简单的模式并分析您的问题,然后我将描述最复杂的模式,它用于 Scala 集合。
首先要注意的是,伴生对象是放置您需要调用的代码的正确位置,而无需类的实例,而在实例方法中使用的帮助器的位置是特征。此外,智能 scala 编译器将为您的 trait 生成一个静态方法,并将所有将使用它的类链接到它。
从您的代码的角度来看,很容易看出如何将其分解为特征,然后通过使用自类型表示法,可以强制仅当特征 Bar 混合时才能混合特征 FooTrait也是。
class Foo extends FooTrait with Bar
trait FooTrait {
self:Bar =>
def foo: Quux = bar(this)
}
trait Bar {
def bar(f: Foo): Quux = frobnicate(f)
}
另请注意,如果您不想通过 Foo 类公开 Bar 接口,另一种方法如下
class Foo extends FooTrait {
protected val barrer = Foo
}
trait FooTrait {
protected val barrer:Bar
def foo: Quux = barrer.bar(this)
}
trait Bar {
def bar(f: Foo): Quux = frobnicate(f)
}
object Foo extends Bar
当您采用单个类和单个伴随对象时,第二种方法工作正常,但当您想要开发类层次结构时,您现在有一个可用于这些类中的每一个的伴随对象,并且您还想要强制伴生对象相对于“伴生类”具有某些特征。
还有一种更复杂的方法,用于 Scala 集合,我强烈建议您不要使用,除非绝对必要。
让我们从 GenTraversable 开始:
trait GenTraversable[+A]
extends GenTraversableLike[A, GenTraversable[A]]
with GenTraversableOnce[A]
with GenericTraversableTemplate[A, GenTraversable]
{
def seq: Traversable[A]
def companion: GenericCompanion[GenTraversable] = GenTraversable
}
object GenTraversable extends GenTraversableFactory[GenTraversable] {
implicit def canBuildFrom[A] = new GenericCanBuildFrom[A]
def newBuilder[A] = Traversable.newBuilder
}
如您所见,特征定义了一个伴生对象,它为构建相同类型的新集合(通常用于过滤、映射等)提供了一些基本的基础设施。
通过在层次结构中向上,您可以看到def companion
已改进:
trait GenIterable[+A]
extends GenIterableLike[A, GenIterable[A]]
with GenTraversable[A]
with GenericTraversableTemplate[A, GenIterable]
{
def seq: Iterable[A]
override def companion: GenericCompanion[GenIterable] = GenIterable
}
object GenIterable extends GenTraversableFactory[GenIterable] {
implicit def canBuildFrom[A] = new GenericCanBuildFrom[A]
def newBuilder[A] = Iterable.newBuilder
}
如果您在类之间浏览,您将了解该机制用于保证对于每个具体的集合实现,在范围内都有一个伴生,该伴生具有与类本身相关的某种属性。这是可能的,因为在子类中细化方法的返回类型是合法的。
然而,为了正常工作,这个机制需要一些手动转换和大量通用参数,以及通用签名。
trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance] {
protected[this] def newBuilder: Builder[A, CC[A]] = companion.newBuilder[A]
/** The generic builder that builds instances of $Coll
* at arbitrary element types.
*/
def genericBuilder[B]: Builder[B, CC[B]] = companion.newBuilder[B]
private def sequential: TraversableOnce[A] =this.asInstanceOf[GenTraversableOnce[A]].seq
// other code
}