๐Ÿ›’ ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ Enum์œผ๋กœ ๊ด€๋ฆฌ

eatnuhยท2022๋…„ 11์›” 13์ผ
5

๊ฐœ๋ฐœ

๋ชฉ๋ก ๋ณด๊ธฐ
1/1
post-thumbnail

0. ์†Œ๊ฐœ

์˜คํ”ˆ๋งˆ์ผ“ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.
์นดํ…Œ๊ณ ๋ฆฌ ๊ตฌํ˜„์— Java Enum์„ ํ™œ์šฉํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

1. ์„ค๊ณ„

์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๊ณ„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„ depth๋Š” ๋˜‘๊ฐ™์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์ƒํ’ˆ์˜ ์ถ”๊ฐ€๋Š” ๋งˆ์ง€๋ง‰ ์นดํ…Œ๊ณ ๋ฆฌ(๋ฆฌํ”„ ์นดํ…Œ๊ณ ๋ฆฌ)์—์„œ๋งŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ƒํ’ˆ์„ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ์กฐํšŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ ์‹œ ์กฐํšŒ ๊ฒฐ๊ณผ๋Š” ํ•˜์œ„ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•œ๋‹ค.

์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด ์œ„ ์‚ฌ์ง„์—์„œ ๋ƒ‰์žฅ/๋ƒ‰๋™ ์ฆ‰์„๋ฐฅ์€ ์ƒํ’ˆ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋งˆ์ง€๋ง‰ ์นดํ…Œ๊ณ ๋ฆฌ ์ด์ง€๋งŒ
๊ฐ™์€ depth์˜ ๋ƒ‰์žฅ/๋ƒ‰๋™๋–ก์— ์ƒํ’ˆ์„ ์ถ”๊ฐ€ํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์‹ํ’ˆ์œผ๋กœ ๊ฒ€์ƒ‰์„ ํ•˜๋ฉด
๊ฐ€๊ณต/์ฆ‰์„์‹ํ’ˆ, ๊ฐ€๋ฃจ/์กฐ๋ฏธ๋ฃŒ/ํ–ฅ์‹ ๋ฃŒ ๋“ฑ๋“ฑ์˜ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๊ด€๋ฆฌ?๐Ÿค”

์ฒ˜์Œ์—๋Š” ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์นดํ…Œ๊ณ ๋ฆฌ ํ…Œ์ด๋ธ”์„ ์„ค๊ณ„ํ•˜๋ ค ํ–ˆ๋Š”๋ฐ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ™์€ ๊ณ„์ธตํ˜• ๊ตฌ์กฐ๋ฅผ ํ…Œ์ด๋ธ”๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ, ์นดํ…Œ๊ณ ๋ฆฌ ๊ด€๋ จ SQL๋„ ๊ต‰์žฅํžˆ ๋ณต์žกํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

stackoverflow์—์„œ ์ฐพ์•„๋ณธ ์ƒํ’ˆ์นดํ…Œ๊ณ ๋ฆฌ ํ…Œ์ด๋ธ”๊ณผ ์กฐํšŒ SQL...

SELECT item.* FROM 
item INNER JOIN categories ON item.category_id = categories.id
WHERE item.is_active = 1 AND (categories.is_active = 1 AND categories.parent_id IN 
    (SELECT id FROM categories WHERE parent_id IS NULL AND is_active = 1)) OR ( item.is_active = 1 AND categories.parent_id IS NULL AND categories.is_active = 1 )

3. Enum์œผ๋กœ ๊ด€๋ฆฌ

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ Enum์œผ๋กœ ๊ด€๋ฆฌ ํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๋Ÿฐํƒ€์ž„ํ™˜๊ฒฝ์—์„œ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  2. Enum์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด DB์ ‘๊ทผ์ด ์—†๋‹ค.
  3. DB๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ํ…Œ์ด๋ธ”๊ณผ ์กฐํšŒ์ฟผ๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์ง„๋‹ค.

์ „์ฒด์ฝ”๋“œ

import java.util.*;
import java.util.stream.Collectors;

public enum Category {

    ROOT("์นดํ…Œ๊ณ ๋ฆฌ", null),
        FASHION("ํŒจ์…˜์˜๋ฅ˜/์žกํ™”", ROOT),
            FASHION_MEN("๋‚จ์„ฑ", FASHION),
                MEN_T_SHIRT("ํ‹ฐ์…”์ธ ", FASHION_MEN), 
                MEN_SWEATSHIRT_HOOD("์Šค์›ป์…”์ธ /ํ›„๋“œ", FASHION_MEN),
                MEN_SHIRT("์…”์ธ ", FASHION_MEN),
                MEN_SUIT("์ •์žฅ", FASHION_MEN),
                MEN_PANTS("๋ฐ”์ง€", FASHION_MEN),
            FASHION_WOMEN("์—ฌ์„ฑ", FASHION),
                WOMEN_T_SHIRT("ํ‹ฐ์…”์ธ ", FASHION_WOMEN),
                WOMEN_BLOUSE("๋ธ”๋ผ์šฐ์Šค/์…”์ธ ", FASHION_WOMEN),
                WOMEN_SWEATSHIRT_HOOD("์Šค์›ป์…”์ธ /ํ›„๋“œ", FASHION_WOMEN),
                WOMEN_SUIT("์ •์žฅ", FASHION_WOMEN),
                WOMEN_ONE_PIECE("์›ํ”ผ์Šค", FASHION_WOMEN),
                WOMEN_SKIRT("์น˜๋งˆ", FASHION_WOMEN),
                WOMEN_PANTS("๋ฐ”์ง€", FASHION_WOMEN),
            UNISEX("๋‚จ๋…€๊ณต์šฉ", FASHION),
                UNISEX_T_SHIRT("ํ‹ฐ์…”์ธ ", UNISEX),
                UNISEX_PANTS("๋ฐ”์ง€", UNISEX),
            BAG_ACC("๊ฐ€๋ฐฉ/์žกํ™”", FASHION),
                BAG("๊ฐ€๋ฐฉ", BAG_ACC),
                    BACKPACK("๋ฐฑํŒฉ", BAG),
                    CROSS_BAG("ํฌ๋กœ์Šค๋ฐฑ", BAG),
                    SHOULDER_BAG("์ˆ„๋”๋ฐฑ", BAG),
                    MINI_BAG("๋ฏธ๋‹ˆ๋ฐฑ", BAG),
                    ECO_BAG("์บ”๋ฒ„์Šค/์—์ฝ”๋ฐฑ", BAG),
                WALLET_BELT("์ง€๊ฐ‘/๋ฒจํŠธ", BAG_ACC),
                    WALLET("์ง€๊ฐ‘", WALLET_BELT),
                    BELT("๋ฒจํŠธ", WALLET_BELT),
            SHOES("์‹ ๋ฐœ", FASHION),
                SNEAKERS("์šด๋™ํ™”/์Šค๋‹ˆ์ปค์ฆˆ", SHOES),
                FLAT_SHOES("๋‹จํ™”/ํ”Œ๋žซ", SHOES),
                HEEL("ํž", SHOES),
                BOOTS("์›Œ์ปค/๋ถ€์ธ ", SHOES),
                SLIPPER("์Šฌ๋ฆฌํผ", SHOES),
            FASHION_CHILDREN("์•„๋™", FASHION),
                GIRL_FASHION("์—ฌ์•„", FASHION_CHILDREN),
                BOY_FASHION("๋‚จ์•„", FASHION_CHILDREN),
        FOOD("์‹ํ’ˆ", ROOT),
            INSTANT("๊ฐ€๊ณต/์ฆ‰์„์‹ํ’ˆ", FOOD),
            BEVERAGE("์ƒ์ˆ˜/์Œ๋ฃŒ", FOOD),
            FRESH("์‹ ์„ ์‹ํ’ˆ", FOOD),
            MEAT_EGG("์ถ•์‚ฐ/๊ณ„๋ž€", FOOD),
            RICE("์Œ€/์žก๊ณก", FOOD),
        DIGITAL("๊ฐ€์ „/๋””์ง€ํ„ธ", ROOT),
            VIDEO("TV/์˜์ƒ๊ฐ€์ „", DIGITAL),
                TV("TV", VIDEO),
                PROJECTOR("ํ”„๋กœ์ ํ„ฐ/์Šคํฌ๋ฆฐ", VIDEO),
            COMPUTER("์ปดํ“จํ„ฐ/๊ฒŒ์ž„/SW", DIGITAL);
    
    // ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„
    private final String title;
  
    // ๋ถ€๋ชจ ์นดํ…Œ๊ณ ๋ฆฌ
    private final Category parentCategory;
    
    // ์ž์‹์นดํ…Œ๊ณ ๋ฆฌ
    private final List<Category> childCategories;

    Category(String title, Category parentCategory) {
        this.childCategories = new ArrayList<>();
        this.title = title;
        this.parentCategory = parentCategory;
        if(Objects.nonNull(parentCategory)) {
        	parentCategory.childCategories.add(this);
        }
    }

    public String getTitle() {
        return title;
    }
    
    // ๋ถ€๋ชจ์นดํ…Œ๊ณ ๋ฆฌ Getter
    public Optional<Category> getParentCategory() {
        return Optional.ofNullable(parentCategory);
    }

    // ์ž์‹์นดํ…Œ๊ณ ๋ฆฌ Getter
    public List<Category> getChildCategories() {
        return Collections.unmodifiableList(childCategories);
    }

    // ๋งˆ์ง€๋ง‰ ์นดํ…Œ๊ณ ๋ฆฌ(์ƒํ’ˆ์ถ”๊ฐ€ ๊ฐ€๋Šฅ)์ธ์ง€ ๋ฐ˜ํ™˜
    public boolean isLeafCategory() {
        return childCategories.isEmpty();
    }

    // ๋งˆ์ง€๋ง‰ ์นดํ…Œ๊ณ ๋ฆฌ(์ƒํ’ˆ์ถ”๊ฐ€ ๊ฐ€๋Šฅ)๋“ค ๋ฐ˜ํ™˜
    public List<Category> getLeafCategories() {
        return Arrays.stream(Category.values())
                .filter(category -> category.isLeafCategoryOf(this))
                .collect(Collectors.toList());
    }
    
    private boolean isLeafCategoryOf(Category category) {
        return this.isLeafCategory() && category.contains(this);
    }

    private boolean contains(Category category) {
        if(this.equals(category)) return true;

        return Objects.nonNull(category.parentCategory) && 
        				this.contains(category.parentCategory);
    }

}

4. ์ •๋ฆฌ

๋น„์Šทํ•œ ๊ณ ๋ฏผํ•˜์‹  ๋ถ„ ์žˆ์œผ๋ฉด ์ด๋ ‡๊ฒŒ ํ• ์ˆ˜๋„ ์žˆ๊ตฌ๋‚˜ ํ•˜๊ณ  ๋ด์ฃผ์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ https://github.com/eatnuh/devthink/tree/main/src/main/resources/1.category

profile
๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ ๋Š๋‚€ ๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ ์ •๋ฆฌ์šฉ ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค!!

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 3์›” 7์ผ

์ข‹์€๊ธ€ ์ž˜๋ดค์Šต๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ