如何制作不需要显式构建方法的类型安全构建器? [英] How do I make a typesafe builder that doesn't need an explicit build method?
问题描述
我正在稍微滥用构建器模式来建立流畅的命令执行链。我所追求的是一种使其成为编译错误的方法,以使最后忘记了execute方法。我的目标是这样的
I am using a slight abuse of the builder pattern to make a fluent imperative execution chain. What I am after is a way to make it a compile error to forget the execute method at the end. My goal is something like the following
WithServiceA {
doStuff()
} WithServiceB {
doStuff()
} withClient client
WithServiceA
和 WithServiceB
都可以返回值,因此,如果使用返回值,则很明显如果返回类型错误,但是如果强制使用它们,则整个物体只是默默地掉在地板上。我想确保无论在什么上下文中使用忘记 withClient
调用都是编译错误。
WithServiceA
and WithServiceB
can both return values, so if the return value is used it is obvious if the return type is wrong, but if they are used imperatively, the whole object just falls on the floor silently. I want to ensure that forgetting the withClient
call is a compile error no matter what context it is used in.
如果不需要块,我希望能够跳过它们并将它们按任意顺序放置,因此我希望替换以前使用的ala嵌套内部类模式
I want to be able to skip blocks if they are unneeded and put them in an arbitrary order so I am looking to replace the nested inner class pattern that I was using previously ala
def onServiceA[A](body: ServiceA => A) = new {
def onServiceB[B >: A](body: ServiceB => B) = {b => {
doStuff()
}
}
推荐答案
它看起来像类型安全的构建器模式。请参见此答案。
It looks like type-safe builder pattern. See 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"))
// ^
您可以为 =:=
类提供自定义替换的自定义错误消息。
You could provide custom error messages with custom replacements for =:=
class.
如果要确保在调用每个 Myclass.apply
withClient
之后,您可以像这样手动调用它:
If you want to be sure that after every Myclass.apply
withClient
will be called, you could call it manually like this:
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
c $ c>方法和 withClient
将至少调用一次。
One can't create Myclass
outside of withContext
method and withClient
will be called at least once.
这篇关于如何制作不需要显式构建方法的类型安全构建器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!