spray中的Magnet模式: typeclass的一种特定方式

Magnet是spray中对type class模式的使用方式,这篇blog主要来自spray作者的:http://spray.io/blog/2012-12-13-the-magnet-pattern/ ,原话中对 Magnet解释:

我们的意图并不是给“type classes”模式一个新名称,而是描述一种为特殊目的而使用的方式。

先看一下他举例在http请求结束(complete)时要做的事情,使用方法重载(method overload)遇到的问题:

1) 因为类型擦拭,会有方法冲突
2) No lifting into a function (of all overloads at the same time)
3) 对包对象中不可用(2.10之前)
4) Code duplication in case of many similar overloads
5) Limitations with regard to parameter defaults
6) Limitations with regard to type inference on arguments

Magnet模式可以解决上面除了最后2点的所有问题。

原先通过方法overload:

def complete[T :Marshaller](status: StatusCode, obj: T): Unit
def complete(future: Future[HttpResponse]): Int
def complete(future: Future[StatusCode]): Int

使用Magnet模式,变成一个方法:

def complete(magnet: CompletionMagnet): magnet.Result = magnet()

看到 magnet封装了行为,以及结果类型

sealed trait CompletionMagnet {
    type Result
    def apply(): Result
}

然后通过隐式转换,让一些类型具备Magnet的能力

object CompletionMagnet {
    implicit def fromStatusObject[T :Marshaller](tuple: (StatusCode, T)) =
        new CompletionMagnet {
            type Result = Unit
            def apply(): Result = ... // implementation using (StatusCode, T) tuple
    }
    implicit def fromHttpResponseFuture(future: Future[HttpResponse]) =
        new CompletionMagnet {
            type Result = Int
            def apply(): Result = ... // implementation using future
    }
    implicit def fromStatusCodeFuture(future: Future[StatusCode]) =
        new CompletionMagnet {
            type Result = Int
            def apply(): Result = ... // implementation using future
    }
}

调用时,会进行隐式转换,下面第一个方法参数是tuple

complete(StatusCodes.OK, "All fine") // returns Unit
complete(someHttpResponseFuture) // returns Int
complete(someStatusCodeFuture) // returns Int

回顾之前blog中介绍过的type class
scala类型系统:26) type classes模式
scala类型系统:27) 回顾常见的type classes

Magnet并没有在声明时使用泛型参数,而是在其内部定义了 type Result,是一个意思。然后对行为方法都命名为apply,方便在执行时以小括号方式调用。

spray中的Magnet模式: typeclass的一种特定方式》上有1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注