在 Java 中抽象出模型构建器上的字段创建

Posted

技术标签:

【中文标题】在 Java 中抽象出模型构建器上的字段创建【英文标题】:Abstracting out the field creation on a model builder in Java 【发布时间】:2021-12-01 04:25:13 【问题描述】:

Insomanyarticleson Java's builder design pattern,实现如下:

public class YourModel 
   // your fields here
   private final long id;
   //...

   private YourModel(YourModelBuilder builder)  
      // set everything from the builder
   
   
   public static class YourModelBuilder  
      // same fields from the model it is trying to build
      private final long id;
      //...

      public YourModelBuilder(long id/* , .... */)  
         // the normal construction pattern here...
         this.id = id;
         //...
      

      // some builder methods for setting individual fields while allowing for chaining


      public YourModel build()  
          YourModel model = new YourModel(this);
          // do validation here
          return model;
      
   

或类似的东西。

这种设计模式的实现似乎满足了我的用例,以一种易于理解的方式为我的 Katalon Studio 测试手动快速轻松地创建模型,但它似乎最终可能成为维护的噩梦,特别是考虑到创建这些模型的 AUT 是不断变化的。

我们如何抽象出从模型复制到模型构建器的字段声明?

【问题讨论】:

Lombok 的 @Builder 可能会有所帮助:projectlombok.org/features/Builder。 这可能正是我要找的!这是否需要我更改 POJO 模型的任何现有实现? 【参考方案1】:

让我们具体说明问题:

您希望能够通过以下任一方式更改模型类:

添加新字段 删除现有字段 重命名现有字段 更改现有字段的类型

并以这样一种方式执行此操作,即您的模型类周围的大部分基础架构(从构建器的“设置器”到您的 toString 实现)都会自动适应,而无需显式地进行修复。

Java 没有那么灵活,因此需要采取严厉措施才能正确执行此操作。你有几个选择:

IDE 工具。使用工具,而不是仅仅在相当于“哑”的编辑器中编辑 java 源文件。例如,许多 IDE 支持字段上的“重构 -> 重命名”的概念,这也会改变你的 setter 中的 this.foo = foo;(如果你有的话)。如果你从未见过这个,它有点神奇,所以我更好地描述它:你选择任何标识符,点击“refactor -> rename”的快捷方式,然后在该标识符周围出现一个小高亮框和所有其他标识符出现的地方。您的 IDE 足够聪明,可以知道范围是什么,并且不会“选择”碰巧共享名称的不同变量;这不是某种“全局搜索/替换”。然后您开始输入,您输入的内容就像魔法一样出现在 ALL 那些小框中。您正在对那些实际引用您选择的事物的标识符进行实时搜索/替换!非常好,这就是 IDE 的全部意义所在。他们了解java,因此可以做一些事情,比如“只修改那些实际引用这个东西的标识符节点”。大多数人不会setFoo 方法名称更改为setBar,但有些人会提供一个弹出窗口,询问这是否是您的意图。如果 IDE 工具/重构系统知道构建器,则可以将其编写为例如通过重构操作添加字段添加字段,更新 equals 和 hashCode 方法,toString 方法,并修复构建器,所有这些都在您输入时一次性完成。我们称之为显式代码生成。请注意,至少对于 eclipse,我不知道重构工具会走得很远。更常见的是,您只需删除所有基础设施,更新您的模型类,然后重新生成 ALL 基础设施。如果你忘记了,你的代码就坏了。重点是:这样的 IDE 插件可能存在,而且构建起来也不是那么困难,所以这是一种选择。我只是不知道实际存在的任何东西。

构建工具和模板。拥有一个系统,您只需编写模型类和一些关于您想要从中获得什么的提示,然后使用它运行构建工具的某些方面:它获取您的模型类和模板提示并生成围绕您的所有基础设施自动需要。这确保了基础设施始终与您的模型类同步,并且与之前的选项不同,它使您的实际(非生成)代码库保持美观和清晰。有一些工具可以做到这一点,但Project Lombok 是唯一一个“在您键入时”工作的工具,直接集成到您的 eclipse 进程中(例如,大纲视图在您键入时更新,例如新的 builder setter 方法)。其余的往往用作注释处理器 - 你需要一个构建周期。我们称之为隐式代码生成

反射富矿是第三种选择:您创建一个实际的模型类,构建器在运行时出现。对于静态和显式类型的 java,这自然不是一个选项,但是如果与模型交互的所有代码都是动态的,例如因为它是用 javascript 或 groovy 或类似语言编写的,那么您可以使其工作。我假设您对此不感兴趣,因此我不会详细介绍如何设置它。这种解决方案在动态语言中非常很常见。无论哪种方式,您都会在编写时失去自省,除非反射工具附带 IDE 插件,此时它与前两种解决方案一样复杂。

选择你的毒药。我会选择隐式代码生成选项,然后我会使用最紧密集成的工具,通过保持“等待构建!”来保持生产力。降到最低限度。但是,我是 Project Lombok 的核心贡献者之一,所以我可能有点 tad 偏见:)

【讨论】:

感谢您的信息!我已经在使用模型构建器,但是出于不同的目的,并且与非常流行的实现教科书和网站喜欢提供的不同:我用它来映射数据文件中的行,映射到我在 Katalon 中使用的模型工作室测试用例。但是,我将直接在测试代码本身中创建模型,但也有健全性测试和负面测试。并且查看管道中的数据文件更改让我想研究这种流行的子生成器类设计模式。我可能会把它留给龙目岛!

以上是关于在 Java 中抽象出模型构建器上的字段创建的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:当我抛出异常时,构建器在未来的构建器中调用了两次

序列化器上的 Django Rest Framework 条件字段

图像未在主要发布时显示,但在“场景”构建器上显示

目标 C 中选择器上的 EXC_BAD_ACCESS

模型和分类器上的 GridSearch

Forge 查看器上的 3D 标记