Enum với nhiều thuộc tính boolean


11

Tôi hiện đang làm việc trên một ứng dụng web nơi chúng ta thường cần đưa ra một số logic máy chủ dựa trên trang sẽ được trả lại cho người dùng.

Mỗi trang được cung cấp một mã trang gồm 4 chữ cái và các mã trang này hiện được liệt kê trong một lớp dưới dạng Chuỗi tĩnh:

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

Và thường trong mã chúng ta thấy mã như thế này ( mẫu thứ 1 ):

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
} 

Điều này thật kinh khủng khi đọc bởi vì nó không hiển thị thuộc tính chung nào của các trang này đã khiến tác giả của mã đặt chúng ở đây. Chúng ta phải đọc mã trong ifchi nhánh để hiểu.

Giải pháp tạm thời

Những ifphần này đã được đơn giản hóa bằng cách sử dụng danh sách các trang được khai báo bởi những người khác nhau trong các lớp khác nhau. Điều này làm cho mã trông giống như ( mẫu thứ 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
} 

... Đó là thể hiện ý định tốt hơn nhiều. Nhưng...

Vấn đề hiện tại

Vấn đề ở đây là nếu chúng ta thêm một trang, về lý thuyết chúng ta cần phải đi qua tất cả các cơ sở mã để tìm xem chúng ta có cần thêm trang của mình vào một if()hoặc vào danh sách như vậy không.

Ngay cả khi chúng tôi đã chuyển tất cả các danh sách đó sang PageCodeslớp dưới dạng hằng số tĩnh, nó vẫn cần kỷ luật từ các nhà phát triển để kiểm tra xem trang mới của họ có phù hợp với bất kỳ danh sách nào không và thêm nó vào danh sách đó.

Giải pháp mới

Giải pháp của tôi là tạo ra một enum (vì có một danh sách mã trang nổi tiếng hữu hạn) trong đó mỗi trang chứa một số thuộc tính mà chúng ta cần đặt:

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
}

Sau đó, mã điều kiện bây giờ trông như thế này ( mẫu thứ 3 ):

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

Mà rất dễ đọc. Ngoài ra, nếu ai đó cần thêm một trang, anh ấy / cô ấy buộc phải suy nghĩ về từng boolean và liệu điều này là đúng hay sai cho trang mới của anh ấy.

Vấn đề mới

Một vấn đề tôi thấy là sẽ có khoảng 10 booleans như thế này, điều này làm cho hàm tạo thực sự lớn và có thể khó có được khai báo ngay khi bạn thêm một trang. Có ai có một giải pháp tốt hơn?

Câu trả lời:


13

Bạn có thể đưa ý tưởng thêm một bước nữa và xác định enum cho các tính năng trang của bạn thay vì sử dụng booleans.

Điều này giúp dễ dàng thêm / xóa một tính năng vào một trang và làm cho các định nghĩa trang có thể đọc được ngay lập tức ngay cả khi có 30-40 tính năng tiềm năng.

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

Tôi đã nghĩ về điều này, nhưng ở đây, nhà phát triển không bị buộc phải đưa ra câu trả lời cho tất cả các câu hỏi "nó có phải là một trang không?", "Nó có một giỏ hàng không?" vv Khi có rất nhiều trong số họ, bạn dễ dàng quên một.
Joffrey

5
@Joffrey Khi bạn nghĩ về nó, có mười booleans cũng không buộc họ phải đưa ra câu trả lời, ít nhất không phải là câu trả lời mà họ nghĩ đến. Kịch bản rất có thể là họ sẽ sao chép định nghĩa của một trang khác hoặc chỉ để IDE điền vào tất cả các tham số false, sau đó sửa đổi một hoặc hai (có thể là sai, vì rất khó để theo dõi). Không có sự bảo vệ hoàn hảo khỏi sự ngu ngốc, và có một điểm mà bạn phải tin tưởng các nhà phát triển của mình để làm điều đúng đắn.
biziclop

Đúng vậy, tôi đã không nghĩ về nó theo cách này :) Và tôi không nghĩ rằng "bằng chứng ngu ngốc" nhỏ do boolean đưa ra là đáng để suy thoái về khả năng chịu trách nhiệm, vì vậy có lẽ tôi sẽ đi theo giải pháp đa dạng. Cảm ơn sự sáng suốt của bạn!
Joffrey

1
Giải pháp tốt, nâng cao. Mặc dù phần của tôi được mã hóa trên 6502s muốn nhồi nhét mọi thứ thành bit. :-)
user949300

@ user949300 giải pháp giống như vararg đầu tiên tôi nghĩ đến thực sự là mặt nạ bit :) nhưng một vararg thực sự với loại enum sạch hơn
Joffrey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.