์คํ๋ง์ผ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ์ํ ์นดํ
๊ณ ๋ฆฌ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํด์ผ ํ์ต๋๋ค.
์นดํ
๊ณ ๋ฆฌ ๊ตฌํ์ Java Enum์ ํ์ฉํ ๋ด์ฉ์
๋๋ค.
์ํ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค๊ณ ํ์ต๋๋ค.
์ฝ๊ฒ ์ค๋ช
ํ๋ฉด ์ ์ฌ์ง์์ ๋์ฅ/๋๋ ์ฆ์๋ฐฅ์ ์ํ์ ์ถ๊ฐํ ์ ์๋ ๋ง์ง๋ง ์นดํ
๊ณ ๋ฆฌ ์ด์ง๋ง
๊ฐ์ depth์ ๋์ฅ/๋๋๋ก์ ์ํ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ๋ํ ์ํ์ผ๋ก ๊ฒ์์ ํ๋ฉด
๊ฐ๊ณต/์ฆ์์ํ, ๊ฐ๋ฃจ/์กฐ๋ฏธ๋ฃ/ํฅ์ ๋ฃ ๋ฑ๋ฑ์ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํฉ๋๋ค.
์ฒ์์๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ๋ก ๊ด๋ฆฌํ๋ ค๊ณ ํ์ต๋๋ค.
๊ทธ๋์ ์นดํ
๊ณ ๋ฆฌ ํ
์ด๋ธ์ ์ค๊ณํ๋ ค ํ๋๋ฐ ์นดํ
๊ณ ๋ฆฌ ๊ฐ์ ๊ณ์ธตํ ๊ตฌ์กฐ๋ฅผ ํ
์ด๋ธ๋ก ํํํ๋ ๊ฒ, ์นดํ
๊ณ ๋ฆฌ ๊ด๋ จ 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 )
๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก Enum์ผ๋ก ๊ด๋ฆฌ ํ๊ธฐ๋ก ํ์ต๋๋ค.
์ ์ฒด์ฝ๋
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);
}
}
๋น์ทํ ๊ณ ๋ฏผํ์ ๋ถ ์์ผ๋ฉด ์ด๋ ๊ฒ ํ ์๋ ์๊ตฌ๋ ํ๊ณ ๋ด์ฃผ์ จ์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.
์์ธํ ๋ด์ฉ https://github.com/eatnuh/devthink/tree/main/src/main/resources/1.category
์ข์๊ธ ์๋ดค์ต๋๋ค!