我可以在Java枚举上使用构建器模式吗 [英] Can I use the builder pattern on a Java Enum

查看:70
本文介绍了我可以在Java枚举上使用构建器模式吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在重新编写一些代码,并且已经确定了重新创建类的方法,因为有固定数量的工作表,所以我将它们创建为枚举。

I'm re-writing some code, and I've decided the way to recreate the class, as there are a fixed number of sheets, I'm creating them as enums. This is a decision based on the readability of a builder patter vs a telescoping constructor.

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

The code I'm grabs some some .xls files, adds headers (and reads some from other .xls files) and perhaps some sub-sheets. It then merges a variety of these sheets together in a specific way to make tabs on a main excel workbook. My issue is that some of the workbook tabs take different numbers of sheets are arguments. I'm trying to apply the builder pattern. This is the sort of code I'm trying to write:

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希望我的枚举声明(以逗号分隔的枚举构造函数列表位于顶部)仅包含构造函数,而不包含其他方法。我可以将这些方法移到下面的 builder方法中,而不会提出投诉。

The error that java is giving me seems to be saying that Java expects my enum declaration (comma delimited list of 'enum constructors' at the top) to only have the constructor in it, and not additional methods. I can move those methods to a 'builder' method below, without complaint.

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

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

Is this the only way to implement a builder pattern on an enum? It does require me to run a separate method, which isn't too much hassle. IT does feel like I'm breaking the pattern though (I guess, not such a bad thing if this works.)

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

N.B I've had a good look around to see if anyone else has asked this question, on SO or elsewhere on the web. The closest I found was a question here on Enums and Factories, but that doesn't quite answer my question. Also I'm aware this isn't quite the builder pattern, as I don't have a separate class that then accepts a build() method that creates a new enum. I guess this is the root of the problem in my initial design, but I am relatively new to Java.

因此,在Java上有没有更好的方法使用构建器模式Java枚举?还是我有足够的距离?

So Is there a better way to use a builder pattern on a Java enum? Or is what I have 'close enough'?

推荐答案

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

Although it doesn't strictly conform to the builder pattern, the short answer is yes. Sort of.

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

The missing piece is not being able to call .build() to instantiate the enum constant, because build() can't use new. But you can get quite a few of the benefits of the builder pattern. And let's face it, you can't use static factory methods, and inline subclassing of enum constants is weird.

下面是使用Country枚举的示例。

Here's an example using a Country enumeration.

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;
    }
}

如果以下情况,您甚至可以在构建器中放入静态工厂方法:

You can even put static factory methods in the builder if you have common ways to build a constant.

因此,它不是Bloch的生成器,但非常接近。

So it's not quite Bloch's builder, but it's pretty close.

这篇关于我可以在Java枚举上使用构建器模式吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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