1

我有一个抽象类(这是一个类似的例子)Printer,它打印提供的参数,除非它未能通过过滤器。 Printer与它的泛型类型是逆变的T

class Printer[-T] {
  val filters: Seq[Function2[T => Boolean]]

  def print(t: T): Unit {
    if (filters.forall(_(t))) doPrint(t)
  }
  def doPrint(t: T): Unit
}

我现在有 20 个子类Printer——一个用于字符串、整数等。由于Printer是逆变的,filters因此必须是val. 但是,如果我想要一种Printer添加过滤器的方法,它需要是不可变的。

def addFilter[TT <: T](t: TT): Printer[TT]

不幸的是,我现在需要在我的 20 个子类中的每一个中实现这个方法。有没有办法解决?

更新:另外,在 中addFilter,我不知道如何返回子类而不是超类Printer。例如,如果我调用addFiltera StringPrinter,理想情况下我会StringPrinter恢复该类型。

4

1 回答 1

1

以下内容与您编写 . 代码的方式有些不同Printer,但可能会实现您的意图。请注意,这种对类进行编码的方式可以更好地分离关注点:您可以doPrint独立于它们的使用方式定义过滤器和打印实现(参数):

case class Printer[T](val filters: List[Function1[T, Boolean]], val doPrint: T => Unit) {
  def print(t: T): Unit = {
    if (filters.forall(_(t))) doPrint(t)
  }

  def addFilter[TT <: T](f: TT => Boolean): Printer[TT] = copy(f :: filters)
}

请注意,我不需要在这里指定逆变性,不确定这是否会成为您的问题。

要使用该类,您不需要子类化,只需将合适的参数传递给构造函数(实际上是apply为案例类免费提供的伴随工厂方法) - 例如:

case class Foo(x: Int)
val fooChk1: Foo => Boolean = (f: Foo) => f.x != 1
val fooPrinter1 = Printer(fooChk1 :: Nil, (f: Foo) => println(s"Foo: x = ${f.x}"))

val fooChk3: Foo => Boolean = (f: Foo) => f.x != 3
val fooPrinter2 = fooPrinter1.addFilter(fooChk3)

val foo3 = Foo(3)
fooPrinter1.print(foo3) // Prints 'Foo: x = 3'
fooPrinter3.print(foo3) // Prints nothing

在这里使用隐式也有相当大的范围 - 参数Print(例如,将构造函数更改为(val filters: List[Function1[T, Boolean]])(implicit val doPrint: T => Unit))和特定Print[X]变体。

于 2013-10-17T03:24:30.707 回答