用于具有不同隐式的库的 Scala 工厂方法
Scala factory method for libraries with different implicits
我想支持 Json 和 Parquet 文件格式。客户端不应该关心它们的实现,但是必须传递一个类型来标识格式。
到目前为止,我有两个 classes 具有这样的签名:
class ParquetFileWriter[T](val path: String)(implicit val writer: ParquetWriter[T]) extends FileWriter[T]
和
class JsonFileWriter[T](val path: String)(implicit writer: JsonWriter[T]) extends FileWriter[T]
他们扩展的特征:
trait FileWriter[T] {
def write(items: Seq[T]): Unit
}
我想通过参数创建一个工厂class来构建class:
class Factory {
def of[T](format: Format): FileWriter[T] = {
format match {
case ParquetSpark =>
new ParquetFileWriter[T](defaultPath)
case Json =>
new JsonFileWriter[T](defaultPath)
}
}
}
问题是 ParquetFileWriter 和 JsonFileWriter 需要隐式(这是我无法控制的,因为它们来自 spray.json 和 com.github.mjakubowski84.parquet4s 库。
如果格式依赖于不同的隐式,我如何为格式实现工厂?我在编译时得到 "could not find implicit value"。
如果你有两个隐含函数,只需添加上下文边界就足够了
class Factory {
def of[T: ParquetWriter : JsonWriter](format: Format): FileWriter[T] = {
format match {
case ParquetSpark =>
new ParquetFileWriter[T]("defaultPath")
case Json =>
new JsonFileWriter[T]("defaultPath")
}
}
}
如果您可能只有这两个隐式之一,请尝试使 Factory
成为一种类型 class
trait Factory[T] {
def of(format: Format): FileWriter[T]
}
trait LowPriorityFactories {
implicit def parquet[T: ParquetWriter]: Factory[T] = {
case ParquetSpark => new ParquetFileWriter[T]("defaultPath")
case _ => throw new Exception
}
implicit def json[T: JsonWriter]: Factory[T] = {
case Json => new JsonFileWriter[T]("defaultPath")
case _ => throw new Exception
}
}
object Factory extends LowPriorityFactories {
def of[T](format: Format)(implicit factory: Factory[T]): FileWriter[T] = factory.of(format)
implicit def jsonParquet[T: JsonWriter : ParquetWriter]: Factory[T] = {
case ParquetSpark => new ParquetFileWriter[T]("defaultPath")
case Json => new JsonFileWriter[T]("defaultPath")
}
}
现在如果你有这两个隐式这适用于 Json
和 ParquetSpark
implicit val jsonWriter: JsonWriter[Int] = null
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int](Json)
Factory.of[Int](ParquetSpark)
如果你只有隐式 JsonWriter
这只适用于 Json
implicit val jsonWriter: JsonWriter[Int] = null
Factory.of[Int](Json)
Factory.of[Int](ParquetSpark) // Exception
如果你只有隐式 ParquetWriter
这只适用于 ParquetSpark
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int](Json) // Exception
Factory.of[Int](ParquetSpark)
另一种选择是使选择更多类型级别将其从运行时转移到编译时(这样你就根本不需要模式匹配,编译错误而不是运行时异常)。
sealed trait Format
case object ParquetSpark extends Format
type ParquetSpark = ParquetSpark.type
case object Json extends Format
type Json = Json.type
trait Factory[T, F <: Format] {
def of: FileWriter[T]
}
object Factory {
def of[T, F <: Format](implicit factory: Factory[T, F]): FileWriter[T] = factory.of
implicit def parquet[T: ParquetWriter]: Factory[T, ParquetSpark] = new Factory[T, ParquetSpark] {
override def of: FileWriter[T] = new ParquetFileWriter[T]("defaultPath")
}
implicit def json[T: JsonWriter]: Factory[T, Json] = new Factory[T, Json] {
override def of: FileWriter[T] = new JsonFileWriter[T]("defaultPath")
}
}
{
implicit val jsonWriter: JsonWriter[Int] = null
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int, Json]
Factory.of[Int, ParquetSpark]
}
{
implicit val jsonWriter: JsonWriter[Int] = null
Factory.of[Int, Json]
// Factory.of[Int, ParquetSpark] // doesn't compile
}
{
implicit val parketWriter: ParquetWriter[Int] = null
// Factory.of[Int, Json] // doesn't compile
Factory.of[Int, ParquetSpark]
}
我想支持 Json 和 Parquet 文件格式。客户端不应该关心它们的实现,但是必须传递一个类型来标识格式。
到目前为止,我有两个 classes 具有这样的签名:
class ParquetFileWriter[T](val path: String)(implicit val writer: ParquetWriter[T]) extends FileWriter[T]
和
class JsonFileWriter[T](val path: String)(implicit writer: JsonWriter[T]) extends FileWriter[T]
他们扩展的特征:
trait FileWriter[T] {
def write(items: Seq[T]): Unit
}
我想通过参数创建一个工厂class来构建class:
class Factory {
def of[T](format: Format): FileWriter[T] = {
format match {
case ParquetSpark =>
new ParquetFileWriter[T](defaultPath)
case Json =>
new JsonFileWriter[T](defaultPath)
}
}
}
问题是 ParquetFileWriter 和 JsonFileWriter 需要隐式(这是我无法控制的,因为它们来自 spray.json 和 com.github.mjakubowski84.parquet4s 库。
如果格式依赖于不同的隐式,我如何为格式实现工厂?我在编译时得到 "could not find implicit value"。
如果你有两个隐含函数,只需添加上下文边界就足够了
class Factory {
def of[T: ParquetWriter : JsonWriter](format: Format): FileWriter[T] = {
format match {
case ParquetSpark =>
new ParquetFileWriter[T]("defaultPath")
case Json =>
new JsonFileWriter[T]("defaultPath")
}
}
}
如果您可能只有这两个隐式之一,请尝试使 Factory
成为一种类型 class
trait Factory[T] {
def of(format: Format): FileWriter[T]
}
trait LowPriorityFactories {
implicit def parquet[T: ParquetWriter]: Factory[T] = {
case ParquetSpark => new ParquetFileWriter[T]("defaultPath")
case _ => throw new Exception
}
implicit def json[T: JsonWriter]: Factory[T] = {
case Json => new JsonFileWriter[T]("defaultPath")
case _ => throw new Exception
}
}
object Factory extends LowPriorityFactories {
def of[T](format: Format)(implicit factory: Factory[T]): FileWriter[T] = factory.of(format)
implicit def jsonParquet[T: JsonWriter : ParquetWriter]: Factory[T] = {
case ParquetSpark => new ParquetFileWriter[T]("defaultPath")
case Json => new JsonFileWriter[T]("defaultPath")
}
}
现在如果你有这两个隐式这适用于 Json
和 ParquetSpark
implicit val jsonWriter: JsonWriter[Int] = null
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int](Json)
Factory.of[Int](ParquetSpark)
如果你只有隐式 JsonWriter
这只适用于 Json
implicit val jsonWriter: JsonWriter[Int] = null
Factory.of[Int](Json)
Factory.of[Int](ParquetSpark) // Exception
如果你只有隐式 ParquetWriter
这只适用于 ParquetSpark
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int](Json) // Exception
Factory.of[Int](ParquetSpark)
另一种选择是使选择更多类型级别将其从运行时转移到编译时(这样你就根本不需要模式匹配,编译错误而不是运行时异常)。
sealed trait Format
case object ParquetSpark extends Format
type ParquetSpark = ParquetSpark.type
case object Json extends Format
type Json = Json.type
trait Factory[T, F <: Format] {
def of: FileWriter[T]
}
object Factory {
def of[T, F <: Format](implicit factory: Factory[T, F]): FileWriter[T] = factory.of
implicit def parquet[T: ParquetWriter]: Factory[T, ParquetSpark] = new Factory[T, ParquetSpark] {
override def of: FileWriter[T] = new ParquetFileWriter[T]("defaultPath")
}
implicit def json[T: JsonWriter]: Factory[T, Json] = new Factory[T, Json] {
override def of: FileWriter[T] = new JsonFileWriter[T]("defaultPath")
}
}
{
implicit val jsonWriter: JsonWriter[Int] = null
implicit val parketWriter: ParquetWriter[Int] = null
Factory.of[Int, Json]
Factory.of[Int, ParquetSpark]
}
{
implicit val jsonWriter: JsonWriter[Int] = null
Factory.of[Int, Json]
// Factory.of[Int, ParquetSpark] // doesn't compile
}
{
implicit val parketWriter: ParquetWriter[Int] = null
// Factory.of[Int, Json] // doesn't compile
Factory.of[Int, ParquetSpark]
}