我可以在 Java 枚举上使用构建器模式吗

2024-05-13

我正在重写一些代码,并且我已经决定了重新创建类的方法,因为有固定数量的工作表,我将它们创建为枚举。这是基于构建器模式与伸缩构造器的可读性的决定。

我的代码获取一些 .xls 文件,添加标题(并从其他 .xls 文件中读取一些),也许还有一些子表。然后,它以特定方式将各种工作表合并在一起,以在主 Excel 工作簿上创建选项卡。我的问题是,某些工作簿选项卡采用不同数量的工作表作为参数。我正在尝试应用构建器模式。这是我想要编写的代码:

public enum workBookSheet {
    mySheet1("Name1","mainSheet1.xls",true,1).addSubSheet("pathToSubSheet1.xls"),
    mySheet2("Name2","mainSheet2.xls",true,2).addHeaderSheet("pathToHeaders.xls").addSubsheet("pathtoSubSheet2.xls");

    private String tabName;
    private String mainSheetName;
    private Boolean available;
    private Integer order;
    private String subSheetName;
    private String headerSheetName;

    private workBookSheet(String tabName, String mainSheetName, Boolean available, Integer order){
        this.tabName = tabName;
        this.mainSheetName = mainSheetName;
        this.available = available;
        this.order = order;
    }
    public workBookSheet addSubSheet(String subSheetName){
        this.subSheetName = subSheetName;
        return this;
    }
    public workBookSheet addHeaderSheet(String headerSheetName){
        this.headerSheetName = headerSheetName;
        return this;
    }

}

java 给我的错误似乎是说 Java 期望我的枚举声明(顶部以逗号分隔的“枚举构造函数”列表)仅包含构造函数,而不包含其他方法。我可以将这些方法移至下面的“构建器”方法,而无需抱怨。

public void buildSheets(){
    mySheet1.addSubSheet("pathToSubSheet1.xls");
    mySheet2.addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls");
}

这是在枚举上实现构建器模式的唯一方法吗?它确实需要我运行一个单独的方法,这并不是太麻烦。不过,它确实感觉我正在打破这种模式(我想,如果这有效的话,也不是什么坏事。)

N.B 我已经仔细查看了周围是否有其他人在 SO 或网络上的其他地方问过这个问题。我发现的最接近的是关于枚举和工厂的问题,但这并不能完全回答我的问题。另外我知道这不完全是构建器模式,因为我没有一个单独的类来接受创建新枚举的 build() 方法。我想这是我最初设计中问题的根源,但我对 Java 还比较陌生。

那么有没有更好的方法在 Java 枚举上使用构建器模式呢?或者我所拥有的“足够接近”?


尽管它并不严格符合构建器模式,但简短的答案是肯定的。有点。

缺少的部分是无法调用.build()实例化枚举常量,因为 build() 不能使用new。但是您可以获得构建器模式的很多好处。让我们面对现实吧,您不能使用静态工厂方法,并且枚举常量的内联子类化很奇怪。

以下是使用国家/地区枚举的示例。

package app;

import org.apache.commons.lang.StringUtils;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Set;
import static app.Language.*;
import static com.google.common.base.Preconditions.*;

enum Language {
    ITALIAN,
    ENGLISH,
    MALTESE
}

public enum Country {

    ITALY(new Builder(1, "Italy").addLanguage(ITALIAN)),
    MALTA(new Builder(2, "Malta").addLanguages(MALTESE, ENGLISH, ITALIAN).setPopulation(450_000));

    final private int id;
    final private String name;
    final private Integer population;
    final private Set<Language> languages;

    private static class Builder {

        private int id;
        private String name;
        private Integer population;
        private Set<Language> languages = EnumSet.noneOf(Language.class);

        public Builder(int id, String name) {
            checkArgument(!StringUtils.isBlank(name));

            this.id = id;
            this.name = name;
        }

        public Builder setPopulation(int population) {
            checkArgument(population > 0);

            this.population = population;
            return this;
        }

        public Builder addLanguage(Language language) {
            checkNotNull(language);

            this.languages.add(language);
            return this;
        }

        public Builder addLanguages(Language... language) {
            checkNotNull(language);

            this.languages.addAll(languages);
            return this;
        }
    }

    private Country(Builder builder) {

        this.id = builder.id;
        this.name = builder.name;
        this.population = builder.population;
        this.languages = builder.languages;

        checkState(!this.languages.isEmpty());
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Nullable
    public Integer getPopulation() {
        return population;
    }

    public Set<Language> getLanguages() {
        return languages;
    }
}

如果您有构建常量的常用方法,您甚至可以将静态工厂方法放入构建器中。

所以它不完全是布洛赫的建造者,但也非常接近。

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

我可以在 Java 枚举上使用构建器模式吗 的相关文章

随机推荐

  • 自定义 colorRampPalette 中的颜色条

    我定义了一个 colorRampPalette my colors colorRampPalette c light green yellow orange red 如何为其绘制颜色条 图例 项目 最好仅使用基本包 我正在寻找一个充满该颜色
  • 当没有文件可供下载时,如何避免 SSIS FTP 任务失败?

    我正在使用 SQL Server 2005 并在 SSIS 中创建 ftp 任务 有时会有文件需要通过 ftp 传输 有时则不会 如果没有文件 我不希望任务或包失败 我已将从 ftp 任务到下一个任务的箭头更改为 完成 以便包运行 我已将允
  • 在TImageViewer中,如何获取用户点击图片的位置?

    在TImageViewer控件中 用户可以缩放或平移图片 我的问题是 当用户点击图片时 如何获取用户在图片上的点击位置 尤其是用户可以对图片进行放大 缩小或平移之后 如何获取对应的图片点击位置呢 As shown below How to
  • 问号运算符“?”的含义Haxe 中的参数之前

    这两个函数签名有什么区别 function f i Int 0 function f i Int 0 参数是否带有前缀似乎没有任何区别 两者都编译良好 确实没有理由使用 在这个例子中 但是有一个区别 On a 静态类型目标 https ha
  • 订单编辑页面中的 WooCommerce 自定义字段

    Display custom field Orders edit page add action woocommerce before order itemmeta storage location of order items 10 3
  • 从 iPhone 设备查找当前国家/地区

    我必须在 iPhone 设置中获取当前国家 地区 谁能告诉我如何在 iPhone 应用程序中获取当前国家 地区 我必须使用当前国家 地区来解析需要传递当前国家 地区的 RSS 提要 请帮我找到那个国家 提前致谢 要查找用户选择的语言所在的国
  • 正则表达式贪婪匹配未按预期工作

    我有一个非常基本的正则表达式 我只是不明白为什么它不起作用 所以问题分为两部分 为什么我当前的版本不起作用以及正确的表达方式是什么 规则非常简单 必须至少包含 3 个字符 如果 字符是第一个字符 则必须至少包含 4 个字符 因此 以下情况应
  • 获取 LLVM getelementptr 中的操作数名称

    我正在尝试获取 getelementptr 指令引用的数组的名称 当在实际的 C 代码中使用中间变量对数组进行索引时 这似乎起作用 如下所示 int a 0 i a 3 在这种情况下 我得到以下位码 arrayidx getelementp
  • PassportJS - 自定义回调并将 Session 设置为 false

    是否可以使用自定义回调并禁用会话 在文档中 它显示了如何禁用会话和自定义回调 但如何组合它们 app get login function req res next passport authenticate local function
  • 如何在 Doctrine 中使用 andWhere 和 orWhere ?

    WHERE a 1 AND b 1 Or b 2 AND c 1 OR c 2 我怎样才能在教义中做到这一点 q gt where a 1 q gt andWhere b 1 q gt orWhere b 2 q gt andWhere c
  • 如何更改Appcompat主题中的TimePicker线条颜色?

    如何更改 Appcompat 主题中所选数字之间的 TimePicker 线条颜色 线条是蓝色的 但我需要橙色线条 我将 TimePickerDialog 与 ContextThemeWrapper 一起使用 TimePickerDialo
  • 如何重定向(标头位置)到 html 文件?

    所以我正在 php 中运行一个注册 登录系统 包括 MySQL 出于测试目的 成功登录后 我将用户重定向到 index php 该文件声明用户已登录 并为他提供注销选项 同时 我制作了一个计划使用的实际 html 页面 因此我只是添加了 i
  • 使用 BlobOutputStream 在 Azure 中上传 blob

    我正在尝试直接从流上传 blob 因为我不知道我决定尝试的流的长度这个答案 https stackoverflow com a 24621538 3695939 这不起作用 即使它从流中读取并且不会抛出任何异常 内容也不会上传到我的容器 我
  • Java 8,为什么不是 ZonedTime 类?

    我发现 Java 8 没有等效的分区日期时间 http docs oracle com javase 8 docs api java time ZonedDateTime html但只能与Time a 分区时间类或类似的东西 I know他
  • 多个 Visual Studio 项目抱怨临时文件丢失,因此无法打开。错误代码 &H80070003

    我在终端服务器上运行 Visual Studio 2010 并且已经运行了一段时间 问题相对较少 今天早上 我启动了我的电脑 在英国的长周末期间 似乎出现了以下问题 我有很多项目 但不是我的所有项目 也不是给定解决方案中的所有项目 抱怨无法
  • 每次我添加新的源子文件夹时,Cmake 都会重新编译所有内容

    我有一个项目树 组织如下 MyProjects build project1 CMakeLists txt project2 CMakeLists txt src project1 Project1Class1 h Project1Clas
  • Tridion 2011 SP1 的示例事件系统代码

    现在我们使用的是 Tridion 5 3 对于许多出版物 我们实现了事件系统 例如如果组件已本地化则发送一些邮件通知 或者当工作流程中完成特定活动时发送邮件通知等 我们当前的事件系统是在 Visual Basic 6 0 中实现的 现在当我
  • TCL 脚本 - exec 将文本刷新到我的标准输出

    我怎样才能 冲洗 stdout of the exec命令到我的脚本stdout没有 等待 结果执行返回 例如在下面的脚本中我想要git clone输出立即出现在我的脚本上下文中 usr bin tclsh git outputs prog
  • 从字符串名称返回 FontStyle

    我想编写一个函数 它将返回 FontStyle 并以字符串作为参数 FontStyle f function Italic FontStyles Italic 我不想编写 Switch case 或 if else 语句来执行相同的操作 对
  • 我可以在 Java 枚举上使用构建器模式吗

    我正在重写一些代码 并且我已经决定了重新创建类的方法 因为有固定数量的工作表 我将它们创建为枚举 这是基于构建器模式与伸缩构造器的可读性的决定 我的代码获取一些 xls 文件 添加标题 并从其他 xls 文件中读取一些 也许还有一些子表 然