枚举具有很多布尔属性


11

我目前正在开发一个webapp,我们经常需要根据要返回给用户的页面来调整一些服务器逻辑。

每个页面都有一个4个字母的页面代码,这些页面代码当前在类中作为静态字符串列出:

public class PageCodes {
    public static final String FOFP = "FOFP";
    public static final String FOMS = "FOMS";
    public static final String BKGD = "BKGD";
    public static final String ITCO = "ITCO";
    public static final String PURF = "PURF";
    // etc..
}

通常在代码中,我们会看到这样的代码(第一种形式):

if (PageCode.PURF.equals(destinationPageCode) || PageCodes.ITCO.equals(destinationPageCode)) {
    // some code with no obvious intent
} 
if (PageCode.FOFP.equals(destinationPageCode) || PageCodes.FOMS.equals(destinationPageCode)) {
    // some other code with no obvious intent either
} 

那种读起来太可怕了,因为它没有显示出这些页面的共同特性导致代码的作者将它们放在这里。我们必须阅读if分支中的代码才能理解。

当前解决方案

if使用不同类别的不同人员声明的页面列表可以部分简化这些内容。这使代码看起来像(第二种形式):

private static final List<String> pagesWithShoppingCart = Collections.unmodifiableList(Arrays.asList(PageCodes.ITCO, PageCodes.PURF));
private static final List<String> flightAvailabilityPages = Collections.unmodifiableList(Arrays.asList(PageCodes.FOMS, PageCodes.FOFP));

// later in the same class
if (pagesWithShoppingCart.contains(destinationPageCode)) {
    // some code with no obvious intent
} 
if (flightAvailabilityPages.contains(destinationPageCode)) {
    // some other code with no obvious intent either
} 

...这可以更好地表达其意图。但...

当前问题

这里的问题是,如果我们添加页面,则理论上我们将需要遍历所有代码库以查找是否需要将页面添加if()至这样的列表或列表中。

即使我们将所有这些列表PageCodes作为静态常量移到了类中,它仍然需要开发人员的纪律,以检查他们的新页面是否适合这些列表中的任何一个,并相应地添加它。

新解决方案

我的解决方案是创建一个枚举(因为存在一个有限的知名页面代码列表),其中每个页面都包含一些我们需要设置的属性:

public enum Page {
    FOFP(true, false),
    FOMS(true, false),
    BKGD(false, false),
    PURF(false, true),
    ITCO(false, true),
    // and so on

    private final boolean isAvailabilityPage;
    private final boolean hasShoppingCart;

    PageCode(boolean isAvailabilityPage, boolean hasShoppingCart) {
        // field initialization
    }

    // getters
}

然后,条件代码现在看起来像这样(第三个形式):

if (destinationPage.hasShoppingCart()) {
    // add some shopping-cart-related data to the response
}
if (destinationPage.isAvailabilityPage()) {
    // add some info related to flight availability
}

这是非常可读的。另外,如果某人需要添加页面,则他/她被迫考虑每个布尔值以及对于他的新页面来说这是对还是错。

新问题

我看到的一个问题是,可能会有10个这样的布尔值,这使构造函数变得很大,并且在添加页面时可能很难正确地声明。有谁有更好的解决方案?

Answers:


13

您可以更进一步,并为页面功能定义一个枚举,而不是使用布尔值。

这样就可以轻松地向页面添加/删除功能,并且即使存在30-40个潜在功能,也可以立即读取页面定义。

public enum PageFeature {
    AVAIL_PAGE,
    SHOPPING_CART;
}

public enum Page {
    FOFP(AVAIL_PAGE),
    FOMS(AVAIL_PAGE),
    BKGD(),
    PURF(SHOPPING_CART, AVAIL_PAGE),

    private final EnumSet<PageFeature> features;

    PageCode(PageFeature ... features) {
       this.features = EnumSet.copyOf(Arrays.asList(features));
    }

    public boolean hasFeature(PageFeature feature) {
       return features.contains(feature);
    }
 }

我考虑了一下,但是在这里,开发人员并没有被迫回答所有问题“页面是否可用?”,“它有购物车吗?”的答案。等等。当它们很多时,您很容易忘记它们。
乔佛里

5
@Joffrey当您考虑时,拥有十个布尔值也不会强迫他们给出答案,至少不是他们所考虑的答案。最有可能的情况是,他们将只复制另一个页面的定义,或者只是让IDE用填充所有参数false,然后修改一个或两个(可能是错误的一个,因为很难跟踪)。没有完美的保护措施可以防止愚蠢,有一点您必须信任开发人员来做正确的事情。
biziclop '16

是的,我没有这样考虑:)而且我不认为布尔值给出的额外的“防傻瓜”小值值得降低可简化性,因此我可能会使用vararg解决方案。感谢您的见解!
乔佛里

1
好的解决方案,被赞成。虽然我对6502s进行编码的部分希望将所有内容都塞进位。:-)
user949300 '16

@ user949300我想到的第一个类似vararg的解决方案实际上是位掩码:),但是带有枚举类型的真正vararg更加干净
Joffrey
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.