如何制作不需要显式构建方法的类型安全构建器?
How do I make a typesafe builder that doesn't need an explicit build method?
我稍微滥用了构建器模式来制作流畅的命令式执行链。我所追求的是一种使它成为 编译错误 以忘记最后执行方法的方法。我的目标如下
WithServiceA {
doStuff()
} WithServiceB {
doStuff()
} withClient client
WithServiceA
和WithServiceB
都可以是return值,所以如果使用return值很明显如果return类型是错误的,但如果命令式地使用它们,整个对象就会静静地落在地板上。我想确保 忘记 withClient
调用是一个编译 错误,无论它在什么上下文中使用。
我希望能够跳过不需要的块并将它们按任意顺序排列,因此我希望替换我之前使用的嵌套内部 class 模式 ala
def onServiceA[A](body: ServiceA => A) = new {
def onServiceB[B >: A](body: ServiceB => B) = {b => {
doStuff()
}
}
它看起来像类型安全的构建器模式。参见 this answer。
你的情况:
trait TTrue
trait TFalse
class Myclass[TA, TB, TC] private(){
def withServiceA(x: => Unit)(implicit e: TA =:= TFalse) = {x; new Myclass[TTrue, TB, TC]}
def withServiceB(x: => Unit)(implicit e: TB =:= TFalse) = {x; new Myclass[TA, TTrue, TC]}
def withServiceC(x: => Unit)(implicit e: TC =:= TFalse) = {x; new Myclass[TA, TB, TTrue]}
def withClient(x: => Unit)(implicit e1: TA =:= TTrue, e2: TB =:= TTrue) = x
}
object Myclass{
def apply() = new Myclass[TFalse, TFalse, TFalse]
}
用法:
Myclass()
.withClient(println("withClient"))
//<console>:22: error: Cannot prove that TFalse =:= TTrue.
// .withClient(println("withClient"))
// ^
Myclass()
.withServiceB(println("with B"))
.withServiceA(println("with A"))
.withClient(println("withClient"))
//with B
//with A
//withClient
Myclass()
.withServiceA(println("with A"))
.withServiceC(println("with C"))
.withServiceB(println("with B"))
.withClient(println("withClient"))
//with A
//with C
//with B
//withClient
Myclass()
.withServiceC(println("with C"))
.withServiceB(println("with B"))
.withServiceA(println("with A"))
.withServiceC(println("with C2"))
.withClient(println("withClient"))
//<console>:25: error: Cannot prove that TTrue =:= TFalse.
// .withServiceC(println("with C2"))
// ^
您可以为 =:=
class.
提供带有自定义替换的自定义错误消息
如果你想确保在每个 Myclass.apply
withClient
之后被调用,你可以像这样手动调用它:
sealed class Context private()
object Context {
def withContext(f: Context => Myclass[TTrue, TTrue, _])(withClient: => Unit) =
f(new Context).withClient(withClient)
}
object Myclass{
def apply(c: Context) = new Myclass[TFalse, TFalse, TFalse]
}
用法:
Context
.withContext(
Myclass(_)
.withServiceA(println("with A"))
.withServiceC(println("with C"))
.withServiceB(println("with B"))
)(println("withClient"))
无法在 withContext
方法之外创建 Myclass
,并且 withClient
将至少被调用一次。
我稍微滥用了构建器模式来制作流畅的命令式执行链。我所追求的是一种使它成为 编译错误 以忘记最后执行方法的方法。我的目标如下
WithServiceA {
doStuff()
} WithServiceB {
doStuff()
} withClient client
WithServiceA
和WithServiceB
都可以是return值,所以如果使用return值很明显如果return类型是错误的,但如果命令式地使用它们,整个对象就会静静地落在地板上。我想确保 忘记 withClient
调用是一个编译 错误,无论它在什么上下文中使用。
我希望能够跳过不需要的块并将它们按任意顺序排列,因此我希望替换我之前使用的嵌套内部 class 模式 ala
def onServiceA[A](body: ServiceA => A) = new {
def onServiceB[B >: A](body: ServiceB => B) = {b => {
doStuff()
}
}
它看起来像类型安全的构建器模式。参见 this answer。
你的情况:
trait TTrue
trait TFalse
class Myclass[TA, TB, TC] private(){
def withServiceA(x: => Unit)(implicit e: TA =:= TFalse) = {x; new Myclass[TTrue, TB, TC]}
def withServiceB(x: => Unit)(implicit e: TB =:= TFalse) = {x; new Myclass[TA, TTrue, TC]}
def withServiceC(x: => Unit)(implicit e: TC =:= TFalse) = {x; new Myclass[TA, TB, TTrue]}
def withClient(x: => Unit)(implicit e1: TA =:= TTrue, e2: TB =:= TTrue) = x
}
object Myclass{
def apply() = new Myclass[TFalse, TFalse, TFalse]
}
用法:
Myclass()
.withClient(println("withClient"))
//<console>:22: error: Cannot prove that TFalse =:= TTrue.
// .withClient(println("withClient"))
// ^
Myclass()
.withServiceB(println("with B"))
.withServiceA(println("with A"))
.withClient(println("withClient"))
//with B
//with A
//withClient
Myclass()
.withServiceA(println("with A"))
.withServiceC(println("with C"))
.withServiceB(println("with B"))
.withClient(println("withClient"))
//with A
//with C
//with B
//withClient
Myclass()
.withServiceC(println("with C"))
.withServiceB(println("with B"))
.withServiceA(println("with A"))
.withServiceC(println("with C2"))
.withClient(println("withClient"))
//<console>:25: error: Cannot prove that TTrue =:= TFalse.
// .withServiceC(println("with C2"))
// ^
您可以为 =:=
class.
如果你想确保在每个 Myclass.apply
withClient
之后被调用,你可以像这样手动调用它:
sealed class Context private()
object Context {
def withContext(f: Context => Myclass[TTrue, TTrue, _])(withClient: => Unit) =
f(new Context).withClient(withClient)
}
object Myclass{
def apply(c: Context) = new Myclass[TFalse, TFalse, TFalse]
}
用法:
Context
.withContext(
Myclass(_)
.withServiceA(println("with A"))
.withServiceC(println("with C"))
.withServiceB(println("with B"))
)(println("withClient"))
无法在 withContext
方法之外创建 Myclass
,并且 withClient
将至少被调用一次。