Енум з великою кількістю булевих властивостей


11

В даний час я працюю над веб-сервером, де нам часто потрібно визначати певну логіку сервера на основі сторінки, яку потрібно повернути користувачеві.

Кожній сторінці надається 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гілці, щоб зрозуміти.

Поточне рішення

Ці ifs частково спрощені з використанням списків сторінок , які оголошуються різними людьми в різних класах. Це робить код таким чином ( 2 клас ):

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класу як статичні константи, він все ще потребує дисципліни від розробників, щоб перевірити, чи вписується їх нова сторінка в якийсь із цих списків, і додати її відповідно.

Нове рішення

Моє рішення полягало в тому, щоб створити enum (оскільки існує кінцево відомий список кодів сторінок), де кожна сторінка містить деякі властивості, які нам потрібно встановити:

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
}

Тоді умовний код тепер виглядає приблизно так ( 3 клас ):

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

Що дуже читабельно. Крім того, якщо комусь потрібно додати сторінку, він змушений замислюватися над кожним булевим і чи це правда чи неправда для його нової сторінки.

Нова проблема

Я бачу одну проблему в тому, що, можливо, буде 10 булеонів на кшталт цього, що робить конструктор справді великим, і, можливо, буде складно правильно визначити декларацію, коли ви додасте сторінку. Хтось має краще рішення?

Відповіді:


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

Правильно, я не думав про це таким чином :) І я не думаю, що невеликий додатковий "нерозумний", що дається булевим, вартий деградації в доступності, тому я, мабуть, піду з рішенням vararg. Дякуємо за ваше розуміння!
Джоффрі

1
Гарне рішення, прихильне. Хоча частина мене, кодована в 6502, хоче все це розбити. :-)
user949300

@ user949300 Перше рішення, схоже на вараг, про яке я думав - це насправді бітові маски :), але справжній вараг із типом перерахунку чистіший
Joffrey
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.