随着Java 8 lambdas的出现,甚至在此之前,出现了许多使用 流畅API模式的API。在Java中列举其中一些API实例包括:
Java Stream APIJava Time APIJPA Query BuilderLombok builders虽然这种模式非常精细,但有两种情况会变得不那么流畅:条件阶段和阶段重用。
Java案例
让我们使用流利的构建器来研究这个问题。为了保持最前沿,让我们使用实验性的Lombok的SuperBuilder注释处理器,它出现在版本1.18.2中,因为这个构建器适合这里描述的场景。请注意,IntelliJ IDEA尚不支持此代码生成器,因此如果您在那里打开项目,您可能会看到很多红色代码,但代码可以运行并可以在Maven上编译。
首先,让我们定义一个域模型。
现在,让我们在正常情况下构建对象:
在上面的示例中,可能存在会话对象在匿名用户的情况下为空的情况。这种情况的天真处理可能如下所示:
但是,在此示例中,我们在对象之间创建了额外的耦合。现在,代码依赖于知道安全字段的默认值。目前,它是null,但在将来,默认值可能会更改为字符串 “anonymous”,我们的代码将会中断。因此,最好完全跳过这个阶段,如下所示:
突然间,我们的代码不那么美观和流畅。此外,当我们处理基类中的字段并且我们需要在其他地方使用相同的检查时,我们可以将它抽象为实用程序方法:
并且,重用它:
代码有点好,但是在两种情况下调用的节奏仍然被打破,并且它感觉不流畅。我们只有一个重用阶段,但考虑到有几个阶段的情况。代码可能变得非常毛茸茸。
介绍过程方法
要解决这些问题,我们可以使用一个简单的 T process(Function) 方法,只需调用作为参数传递的函数和构建器引用。在此示例中,我们扩展了Lombok生成的构建器,如下所示:
然后,对于可选阶段,我们可以更加流畅地实现上述两个场景。
阶段结果:
节奏仍然有点突破,但它发生在本地层面,而不是全球层面。在我们调用我们的特殊操作后,处理继续正常进行。并且,那里没有用户可见的分配。在使用复杂的API(如JPA Query Builder)时,经常需要进行这种自定义阶段处理。缺乏这种简单的方法有时会导致非常复杂和毛茸茸的代码。
Groovy案例
Groovy案例更复杂,因为目前存在类型推断和编译IDEA代码的一些问题。提供的代码与Maven一起正常工作,但如果我们使用@CompileStatic 注释,它在IntelliJ IDEA中失败 。首先,我们定义一个扩展方法(我使用Java,因为Groovy在这里抱怨泛型边界):
然后,我们需要在文件中注册扩展 META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule,L IKE以下。使用Groovy 2.5.0之前的旧版本 METAINF/services/org.codehaus.groovy.runtime.ExtensionModule,但这种用法与Java 11不完全兼容,因此文件的路径已更改,而旧路径仍支持兼容性:
注意:我们也将Java类注册 SecurityUtil 为扩展,因为它遵循Groovy扩展方法的模式。然后,我们可以使用我们的新方法进行可选处理:
重用代码:
而且,即使是自定义阶段,该方法来自于 SecurityUtil 类:
代码看起来和Kotlin代码一样好,但由于Groovy的动态特性,还需要一些额外的工作。
结论
这种模式实现起来非常简单,但它可以在复杂场景中增加大量可用性。如果您正在设计一个流畅的API,我建议您在API中添加这样的方法。它不会伤害任何东西,但它可以使用户代码看起来更好一点。
如果您使用Kotlin,Groovy或其他一些带有扩展方法的JVM语言,则无需等到API设计人员将这样的方法添加到其流畅的API。在具有扩展方法的语言中,可以在需要时立即使用自定义扩展方法开始使用此模式。
对于Java项目,我们仍然需要等待API设计者支持这种模式,因为将自己的方法插入API并不总是那么容易。如果您自己是流畅的API设计师,请考虑添加一个简单的方法,如 T process(Funtion)API。这可以帮助用户更灵活地使用您的API。