我有一个抽象类(这是一个类似的例子)Printer
,它打印提供的参数,除非它无法通过过滤器。 Printer
是逆变的w.r.t.它的通用类型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
子类 - 一个用于字符串,Ints等。由于Printer
是逆变的,filters
必须是val
。但是,如果我想要一个Printer
的方法来添加过滤器,那么它需要是不可变的。
def addFilter[TT <: T](t: TT): Printer[TT]
不幸的是,我现在需要在我的20个子类中的每个子类中实现此方法。有没有办法解决这个问题?
更新:此外,在addFilter
中,我不知道如何返回子类而不是超类Printer
。例如,如果我在addFilter
上调用了StringPrinter
,我理想情况下会返回StringPrinter
类型。
答案 0 :(得分: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]
变量