用反思改进一般论点

  • 本文关键字: scala generics reflection
  • 更新时间 :
  • 英文 :


以下是我目前正在处理的Http客户端的简化:

class Request[A]( val url: String, val event: Callbacks[A] )
{
    def run: Try[A] = ...
}
case class Image( override val url: String, override val event: Callbacks[Bitmap] ) extends Request[Bitmap]

object GET
{
    def apply[A <: Request[B] : ClassTag, B : ClassTag]( url: String, event: Callbacks[B] ): Try[B] =
    {
        classOf[A]
            .runtimeClass
            .getConstructor( classOf[String], classOf[Callbacks[B]] )
            .newInstance( url, event )
            .asInstanceOf[A]
            .run
    }
}

object Main extends App
{
    GET[Image, Bitmap]( "http://...", null )
}

我想改进我的API,以便我可以像这样调用GET

GET[Image]( "http://...", null )

提供泛型参数Image应该意味着我正在使用Bitmap,因此我不想再次指定它。

您可以使用类似于CanBuildFrom的模式:使用隐式生成器来创建合适的Request:

某些类型:

abstract class Content
class Bitmap extends Content
class Callbacks[T]
abstract class Request[C <: Content](val url: String, val event: Callbacks[C]) {
  def run: C
}
class ImageRequest(_url: String, _event: Callbacks[Bitmap]) 
  extends Request[Bitmap](_url, _event) {
  def run: Bitmap = {
    new Bitmap()
  }
}

现在是隐式参数RequestBuilder:的类型

abstract class RequestBuilder[C <: Content] {
  def create(url: String, event: Callbacks[C]): Request[C]
}
class ImageRequestBuilder extends RequestBuilder[Bitmap]() {
  def create(url: String, event: Callbacks[Bitmap]): ImageRequest = {
    new ImageRequest(url, event)
  }
}
object ImplicitContainer {
  implicit val ImplicitImageRequestBuilder = new ImageRequestBuilder()
}

像这样使用:

object GET {
  def apply[C <: Content](url: String, event: Callbacks[C])
                         (implicit rb: RequestBuilder[C]): C = {
    rb.create(url, event).run
  }
}
object HttpClient extends App {
  import ImplicitContainer._
  val bitmap = GET[Bitmap]("http://...", null)
  println(bitmap)
}

这样,当您调用GET时,您总是会收到不同的请求

我能得到的最接近的方法是提供一个隐式参数,并将我的所有结果映射器(Image、Html…)注册为隐式值。由于附加的隐式定义,这增加了一些配置开销,但带来了更好的定制优势。这样我也可以去掉反射部分。

implicit val image = Image.apply _

object GET
{
    def apply[T]( url: String, event: Callbacks[T] )( implicit request: ( String, Callbacks[T] ) => Request[T] ): Try[T] =
    {
        request( url, event ).run
    }
}

import image
GET[Bitmap]( "http://...", null )
GET[Bitmap]( "http://...", null )( myOwnAwesomeImageProcessor _ )

相关内容

  • 没有找到相关文章

最新更新