1

我正在设计一个 API。它基本上看起来像这样:

trait Service {

    def performUseCase[T](transferObjects: Iterable[TransferObject[T]])

}

trait TransferObject[T] {

    def data: T

}

case class TransferObjectA[T](data: T) extends TransferObject[T]
case class TransferObjectB[T](data: T) extends TransferObject[T]

注意:如有必要,我可以更改TransferObjects. 语义上重要的是:

  1. s至少有两种TransferObject
  2. 传输对象必须以任何方式构建顺序。现在如何构建该订单并不那么重要:一个Seq[TransferObject[_]或一个传输对象引用下一个或然而。

Service特征将有不同的实现。对于每个Service实例,必须指定该实例可以处理的类型。

示例:此服务val myService = MyService()可以处理TransferObjects[MyTypeA]等等TransferObjects[MyTypeB]。当 API 用户尝试传递一个TransferObjects[MyUnknownType]编译器应该抛出一个错误。

我阅读了有关 Scala 的类型系统、类型类(例如隐式)和类型声明的信息,但我还不了解所有细节。

我尝试使用Service具有类型特定处理程序的 trait 实现作为类型类。MyHandler[MyTypeA]MyHandler[MyTypeB],并使用隐式传递当前参数类型的正确处理程序。但处理程序不应暴露给 API 用户。这就是为什么我想知道如果用户传入Service无法处理的类型的参数,是否有可能抛出编译器错误。

真正的实现更复杂,目前已被破坏。也许我可以稍后再提供一些代码。


围捕:

再说一遍:我想要多个服务实例。它们中的每一个都应该能够处理多种参数类型。如果传入了未知类型的参数,编译器应该会抛出错误。特定类型的处理程序被视为实现细节,应该对 API 用户隐藏。

我如何意识到这一点?

4

2 回答 2

1

你可以在一些里面使用sealed trait TransferObject[T]{...and和case class TransferObjectA(data: Int) extends TransferObject[Int] ...def performUseCase[T](transferObjects: Iterable[TransferObject[T]])

transferObject match{
case TransferObjectA(myInt) => ...
...
}//throws warning because of unmatched TransferObjectB on compile time because of sealed trait

也看看什么是密封特性?

于 2013-08-14T20:04:27.870 回答
0

这是一种基于类型类的方法:

trait TransferObject[T] {
  def data: T
}

case class TransferObjectA[T](data: T) extends TransferObject[T]
case class TransferObjectB[T](data: T) extends TransferObject[T]

trait Service {
  protected[this] trait Handler[A] {
    def apply(objs: Iterable[TransferObject[A]]): Unit
  }

  def performUseCase[A](objs: Iterable[TransferObject[A]])(
    implicit handler: Handler[A]
  ) = handler(objs)
}

接着:

object MyIntAndStringService extends Service {
  implicit object intHandler extends Handler[Int] {
    def apply(objs: Iterable[TransferObject[Int]]) {
      objs.foreach(obj => printf("Int: %d\n", obj.data))
    }
  }

  implicit object stringHandler extends Handler[String] {
    def apply(objs: Iterable[TransferObject[String]]) {
      objs.foreach(obj => printf("String: %s\n", obj.data))
    }
  }
}

val ints = List(1, 2, 3).map(TransferObjectA(_))
val strings = List("A", "B", "C").map(TransferObjectA(_))
val chars = List('a', 'b', 'c').map(TransferObjectA(_))

最后:

scala> MyIntAndStringService.performUseCase(ints)
Int: 1
Int: 2
Int: 3

scala> MyIntAndStringService.performUseCase(strings)
String: A
String: B
String: C

scala> MyIntAndStringService.performUseCase(chars)
<console>:14: error: could not find implicit value for parameter handler: MyIntAndStringService.Handler[Char]
              MyIntAndStringService.performUseCase(chars)
                                                  ^

如预期的。

于 2013-08-14T20:29:21.100 回答