如何制作不需要显式构建方法的类型安全构建器? [英] How do I make a typesafe builder that doesn't need an explicit build method?

查看:66
本文介绍了如何制作不需要显式构建方法的类型安全构建器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在稍微滥用构建器模式来建立流畅的命令执行链。我所追求的是一种使其成为编译错误的方法,以使最后忘记了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"))

在ideone上

withContext Myclass c $ c>方法和 withClient 将至少调用一次。

One can't create Myclass outside of withContext method and withClient will be called at least once.

这篇关于如何制作不需要显式构建方法的类型安全构建器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆