我有一个数据源的通用参数特征,每个实际源都有案例类
trait AbstractSource {
val name: String
}
case class ConcreteSource(name: String) extends AbstractSource
我还有一个作用于这个数据源的类的特征(源的逆变)
trait AbstractConsumer[-T <: AbstractSource] {
def foo(inp: T): Unit
}
class ConcreteConsumer extends AbstractConsumer[ConcreteSource] {
override def foo(inp: ConcreteSource): Unit =
println(inp.name)
}
我想为我的管道方法创建一个工厂方法,它根据输入数据源创建正确的使用者。我已经尝试了以下但都有错误
object ConsumerFactory {
def create(inp: AbstractSource): AbstractConsumer[_ <: AbstractSource] =
inp match {
case _: ConcreteSource => new ConcreteConsumer()
case _ => ???
}
def createTwo[T <: AbstractSource](inp: T): AbstractConsumer[T] =
inp match {
case _: ConcreteSource => new ConcreteConsumer() // errors "required: AbstractConsumer[T], found: ConcreteConsumer"
case _ => ???
}
}
class Main {
def pipeline[T <: AbstractSource](consumer: AbstractConsumer[T], source: T): Unit =
consumer.foo(source)
def execute(): Unit = {
val consumer: ConcreteSource = ConcreteSource("john")
val source = ConsumerFactory.create(consumer) // errors "found: AbstractConsumer[_$1] where type _$1 <: AbstractSource, required: AbstractConsumer[ConcreteSource]"
val source = ConsumerFactory.createTwo(consumer)
pipeline(source, consumer)
}
}
val x = new Main()
x.execute()
如果我理解正确,问题是我需要向管道提供 AbstractConsumer[T] 的子类型,但由于逆变类型参数,我不知道如何根据输入执行此操作。
最佳答案
恕我直言,使用类型类更容易解决这类问题,如下所示:
trait AbstractConsumer[-S <: AbstractSource] {
def consume(inp: S): Unit
}
object AbstractConsumer {
sealed trait ConsumerFactory[S <: AbstractSource] {
type Consumer <: AbstractConsumer[S]
def createConsumer(): Consumer
}
type Factory[S <: AbstractSource, C <: AbstractConsumer[S]] = ConsumerFactory[S] { type Consumer = C }
object Factory {
def apply[S <: AbstractSource, C <: AbstractConsumer[S]](factory: => C): Factory[S, C] =
new ConsumerFactory[S] {
override final type Consumer = C
override final def createConsumer(): Consumer =
factory
}
}
// Get by type.
def apply[S <: AbstractSource](implicit factory: ConsumerFactory[S]): factory.Consumer =
factory.createConsumer()
// Get by value.
def fromSource[S <: AbstractSource](source: S)(implicit factory: ConsumerFactory[S]): factory.Consumer =
factory.createConsumer()
}
然后具体源将实现类型类,如下所示:
final class ConcreteConsumer extends AbstractConsumer[ConcreteSource] {
override def consume(inp: ConcreteSource): Unit =
println(inp.name)
}
object ConcreteConsumer {
implicit final val ConcreteConsumerFactory: AbstractConsumer.Factory[ConcreteSource, ConcreteConsumer] =
AbstractConsumer.Factory(new ConcreteConsumer())
}
最后,您可以像这样使用它:
import ConcreteConsumer._ // Put the factory in scope.
val source = new ConcreteSource("john")
val consumer1 = AbstractConsumer[ConcreteSource]
val consumer2 = AbstractConsumer.fromSource(source)
如果工厂需要一些参数或其他东西,您可以调整代码。
可以看到运行的代码here .
关于Scala - 如何为逆变类定义工厂方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70981000/