使用构建器模式最多设置一次值

2024-03-27

Java 中是否有标准做法,在使用构建器模式时,确保成员变量最多设置一次。我需要确保 setter 被调用 0 或 1 次,但绝不会更多。我想扔一个RuntimeException某种类型的问题,但我担心同步问题以及该领域的最佳实践。


什么也没有wrong如果用户以您所描述的非法方式调用方法,则会引发异常,但它并不是非常优雅。构建器模式背后的想法是让用户编写流畅、可读的对象定义,而编译时安全性是其中的重要组成部分。如果用户不能确信构建器即使编译也会成功,那么您就引入了用户现在需要理解和解释的额外复杂性。

有几种方法可以完成您所描述的任务,让我们来探讨一下:

  1. 只让用户做他们想做的事

    构建器的一大好处是它们可以让您从同一个构建器构建多个不同的对象:

    List<Person> jonesFamily = new ArrayList<>();
    Person.Builder builder = new Person.Builder().setLastName("Jones");
    
    for(String firstName : jonesFamilyFirstNames) {
      family.add(builder.setFirstName(firstName).build());
    }
    

    我认为你有充分的理由禁止这种行为,但如果我没有指出这个有用的技巧,那就是我的失职。也许您一开始就不需要限制这一点。

  2. 提出异常

    你建议提出一个例外,这肯定会起作用。就像我说的,我不认为这是最优雅的解决方案,但这是一种实现(使用Guava https://code.google.com/p/guava-libraries/'s 前提条件 https://code.google.com/p/guava-libraries/wiki/PreconditionsExplained,为了增加可读性):

    public class Builder {
      private Object optionalObj = null;
      // ...
    
      public Builder setObject(Object setOnce) {
        checkState(optionalObj == null, "Don't call setObject() more than once");
        optionalObj = setOnce;
      }
      // ...
    }
    

    这引发了一个IllegalStateException http://docs.oracle.com/javase/7/docs/api/java/lang/IllegalStateException.html,所以你可以直接打电话throw new IllegalStateException()如果你不使用番石榴(你应该......:))。假设您没有在线程之间传递构建器对象,则应该不会出现同步问题。如果是,您应该进一步思考为什么在不同的线程中需要相同的构建器 - 这几乎肯定是一种反模式。

  3. 根本不提供方法

    这是防止用户调用您不希望他们调用的方法的最干净、最清晰的方法 - 首先不要提供它。相反,重写构建器的构造函数或build()方法,以便他们可以选择在当时传递值,但不能在其他时间传递值。通过这种方式,您可以清楚地保证每个构造的对象最多可以设置一次该值。

    public class Builder {
      // ...
    
      public Obj build() { ... }
      public Obj build(Object onceOnly) { ... }
    }
    
  4. 使用不同的类型来公开某些方法

    我实际上并没有这样做,它可能比它的价值更令人困惑(特别是,您可能需要使用自约束泛型 http://www.artima.com/weblogs/viewpost.jsp?thread=136394对于中的方法Builder),但它是在我写作时想到的,并且对于某些用例来说可能非常明确。将受限制的方法放在构建器的子类中,并且该方法返回父类型,从而防止调用者重新调用该方法。如果这没有意义,一个例子可能会有所帮助:

    public class Builder {
      // contains regular builder methods
    }
    
    public class UnsetBuilder extends Builder {
      public Builder setValue(Object obj) { ... }
    }
    
    // the builder constructor actually returns an UnsetBuilder
    public static UnsetBuilder builder() { ... }
    

    然后我们可以这样调用:

    builder().setValue("A").build();
    

    但是如果我们尝试调用,我们会得到一个编译时错误:

    builder().setValue("A").setValue("B").build();
    

    because setValue()回报Builder,其中缺少一个setValue()方法,从而防止第二种情况。要完全正确这将是很棘手的(如果用户将Builder回到一个UnsetBuilder?)但经过一些努力就会做你正在寻找的事情。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用构建器模式最多设置一次值 的相关文章

  • 在 JTable 中移动行

    我使用 MVC 模式 并且有一个如下所示的 JTable List
  • JavaMail Gmail 问题。 “准备启动 TLS”然后失败

    mailServerProperties System getProperties mailServerProperties put mail smtp port 587 mailServerProperties put mail smtp
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 在Windows上安装Java 11 OpenJDK(系统路径问题)

    Java 11 最近发布了 众所周知 这个版本没有安装文件 当然 要在没有安装程序的情况下安装 Java 我将系统设置 PATH 和 JAVA HOME 设置为解压缩 Java 11 的文件夹的地址 根据对类似问题的已接受回复建议 唯一的事
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • jdbc4.MySQLSyntaxErrorException:数据库中不存在表

    我正在使用 SpringBoot 开发一个网络应用程序 这是我的application properties文件来指定访问数据库的凭据 spring datasource driverClassName com mysql jdbc Dri
  • 如何在jsp代码中导入java库?

    我有以下jsp代码 我想添加 java io 等库 我怎样才能做到这一点
  • Microsoft Graph 身份验证 - 委派权限

    我可以使用 Microsoft Graph 访问资源无需用户即可访问 https developer microsoft com en us graph docs concepts auth v2 service 但是 此方法不允许我访问需
  • 无法理解 Java 地图条目集

    我正在看一个 java 刽子手游戏 https github com leleah EvilHangman blob master EvilHangman java https github com leleah EvilHangman b
  • 在具有相同属性名称的不同数据类型上使用 ModelMapper

    我有两节课说Animal AnimalDto我想用ModelMapper将 Entity 转换为 DTO 反之亦然 但是对于具有相似名称的一些属性 这些类应该具有不同的数据类型 我该如何实现这一目标 动物 java public class
  • 检查 Android 手机上的方向

    如何查看Android手机是横屏还是竖屏 当前配置用于确定要检索的资源 可从资源中获取Configuration object getResources getConfiguration orientation 您可以通过查看其值来检查方向
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • Tomcat 6找不到mysql驱动

    这里有一个类似的问题 但关于类路径 ClassNotFoundException com mysql jdbc Driver https stackoverflow com questions 1585811 classnotfoundex
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • Windows 上的 Nifi 命令

    在我当前的项目中 我一直在Windows操作系统上使用apache nifi 我已经提取了nifi 0 7 0 bin zip文件输入C 现在 当我跑步时 bin run nifi bat as 管理员我在命令行上看到以下消息 但无法运行
  • Keycloak - 自定义 SPI 未出现在列表中

    我为我的 keycloak 服务器制作了一个自定义 SPI 现在我必须在管理控制台上配置它 我将 SPI 添加为模块 并手动安装 因此我将其放在 module package name main 中 并包含 module xml 我还将其放
  • 休眠以持久保存日期

    有没有办法告诉 Hibernate java util Date 应该持久保存 我需要这个来解决 MySQL 中缺少的毫秒分辨率问题 您能想到这种方法有什么缺点吗 您可以自己创建字段long 或者使用自定义的UserType 实施后User
  • java迭代器内部是如何工作的? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个员工列表 List
  • java8 Collectors.toMap() 限制?

    我正在尝试使用java8Collectors toMap on a Stream of ZipEntry 这可能不是最好的想法 因为在处理过程中可能会发生异常 但我想这应该是可能的 我现在收到一个我不明白的编译错误 我猜是类型推理引擎 这是
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐

  • ADT 到 Android Studio 意外的顶级异常

    因此 我正在尝试将 Eclipse ADT 项目迁移到 Android Studio 中 我使用 appcompat v7 项目作为 eclipse 中的库项目 我按照 Android 开发网站上的说明进行操作 但仍然收到此错误 Error
  • `ejabberdctl start` 导致“内核 pid 终止”错误 - 我该怎么办?

    我用谷歌搜索了三个小时但没有结果 我有一个 ejabberd 安装 但不是使用 apt 安装的 它是从源代码安装的 其中没有名为 ejabberd 的程序 启动和停止 一切都是通过 ejabberdctl 进行的 它完美地运行了一个月 突然
  • CDN 上的 Dojo 与自己安装的 Dojo

    我使用了相当多的 Dojo 但迄今为止我仅通过包含来自 AOL Google 等 CDN 来使用它 托管 Dojo 副本而不是通过 CDN 使用它是否有优势 我没有太多需要改变代码库 但我想还有其他优点 缺点 通过托管您自己的 Dojo 环
  • Tornado 如何在任意位置提供单个静态文件?

    我正在使用 Tornado 开发一个简单的网络应用程序 它提供一些动态文件和一些静态文件 动态文件不是问题 但我在提供静态文件时遇到问题 我想做的是在访问 foo json URL 时提供文件 path to foo json 请注意 pa
  • Docker 输出中缺少层 ID

    我刚刚按照官方指南在 Ubuntu 上全新安装了 Docker https docs docker com engine installation linux ubuntulinux https docs docker com engine
  • Laravel 4 如何在视图中显示 Flash 消息?

    我正在尝试显示我的闪存消息 这是我的路由文件中的 Route post users groups save function return Redirect to users groups gt withInput gt with succ
  • RemoteServiceServlet 和 RemoteService 有什么区别?

    我知道第一个是类 第二个是接口 但重点是 为什么客户服务应该扩展远程服务并为服务实现类扩展远程服务Servlet 那么幕后到底是什么 您正在尝试比较苹果和橙子 请阅读docs https developers google com web
  • 是否有一个运算符可以作为 concatMap 但具有多个内部可观察值

    我正在使用可观察的对象来查询我的数据库 该可观察对象将返回一个数组 其中包含找到的所有匹配对象 我的问题是我想将可观察值映射到我将从另一个 API 检索的更多详细信息 我尝试了 concatMap 但它只让我在初始可观察值中嵌套 1 个可观
  • 测试互联网连接的最快方法

    C 2008 SP1 我正在使用此代码连接到我们的客户网站 这是针对软件电话应用程序的 在用户拨打电话之前 软件电话必须测试是否存在有效的互联网连接 因此 我要做的就是使用 httpWebRequest 类连接到我们的客户网站 如果响应正常
  • iPhone 电子邮件应用程序启动 URL

    在 iPhone 上启动电子邮件和开始新电子邮件的 URL 是 mailto 电子邮件受保护 cdn cgi l email protection 我只想启动电子邮件应用程序 将用户放在主菜单或收件箱中 mailto 开始撰写新的空白电子邮
  • 在谷歌应用程序脚本中解析 html 的最佳方法是什么

    var page UrlFetchApp fetch contestURL var doc XmlService parse page 上面的代码在使用时会出现解析错误 但是如果我用已弃用的 Xml 类替换 XmlService 类 并设置
  • 跟踪文件(Windows 终端)的硬链接(重新分析点?)?

    如何跟踪文件的硬链接 重新分析点 管道传输到格式列表不会显示目标 至少在 powershell 7 中 你会得到一个小 ascii 箭头 该文件夹位于 env path 中 如果您没有 Windows 终端 则 MicrosoftEdge
  • 权限是不可更改的权限类型

    背景 我正在尝试新的 Tiles 和 TileService 并决定重新创建 USB Tethering 磁贴CyanogenMod https github com CyanogenMod android frameworks base
  • 现在N层架构意味着什么?

    从传统意义上讲 N 层意味着将应用程序分成 层 并将每个 层 放在不同的服务器上 这样做至少有 3 个原因 维护 a 代码维护 更容易进行错误修复和功能添加 b 硬件维护 关闭一台服务器不会中断其他层的服务 性能 一台服务器的速度通常不够快
  • Python - 在这种情况下列表理解是否有效?

    这是Python中的输入 脏 列表 input list n data1 n data2 n n data3 n 每个列表元素包含带有换行符的空格或带有换行符的数据 使用下面的代码清理它 cleaned up list data strip
  • 在 Archlinux 上通过 Pyenv 编译 Python 但缺少 OpenSSL

    我正在尝试在新安装的 ArchLinux 上通过 pyenv 安装 python pyenv install 3 5 1Downloading Python 3 5 1 tar xz gt https www python org ftp
  • Javascript 字符串替换为计算

    有没有办法解决javascript中字符串中的数学表达式 例如 假设我想生成字符串 Tom has 2 apples Lucy has 3 apples Together they have 5 apples 但我希望能够替换变量 我可以通
  • 基于属性之一的 JSON 模式 anyOf 验证

    我很难弄清楚如何根据其中一个属性的值验证对象数组 所以我有一个 JSON 对象 例如 items name foo otherProperty bar name foo2 otherProperty2 baz otherProperty3
  • initWithNibName 没有被调用

    我需要将一些自定义逻辑放入我的 iPhone 应用程序中 以便根据您运行的 iOS 版本 选择不同的 XIB 文件 即 iPhone 或 iPad 将显示不同的 XIB 文件 我从第一天起就构建了整个 iPhone 应用程序 一切都很好 在
  • 使用构建器模式最多设置一次值

    Java 中是否有标准做法 在使用构建器模式时 确保成员变量最多设置一次 我需要确保 setter 被调用 0 或 1 次 但绝不会更多 我想扔一个RuntimeException某种类型的问题 但我担心同步问题以及该领域的最佳实践 什么也