ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,81 @@
+package christmas.model.order;
+
+import static christmas.exception.ErrorType.INVALID_MAX_MENU_QUANTITY;
+import static christmas.exception.ErrorType.INVALID_MENU_ONLY_DRINK;
+import static christmas.utils.Constants.MAX_ORDER_QUANTITY;
+import static christmas.utils.Constants.MIN_ORDER_MENU;
+
+import christmas.model.order.enums.Category;
+import christmas.model.order.enums.MenuInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class OrderDetail {
+
+    private final OrderMenu orderMenu;
+
+    public OrderDetail(OrderMenu orderMenu) {
+        validate(orderMenu);
+        this.orderMenu = orderMenu;
+    }
+
+    public Map<String, Integer> getOrderMenuName() {
+        Map<String, Integer> details = new HashMap<>();
+        for (Map.Entry<MenuName, MenuQuantity> entry : orderMenu.getOrderMenu().entrySet()) {
+            String menuName = entry.getKey().getName();
+            int quantity = entry.getValue().getQuantity();
+            details.put(menuName, quantity);
+        }
+
+        return Collections.unmodifiableMap(details);
+    }
+
+    public int getQuantityByMenu(MenuName menuName) {
+        return orderMenu.getMenuQuantity(menuName);
+    }
+
+    public List<MenuName> getMainMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containMainMenu)
+                .toList();
+    }
+
+    public List<MenuName> getDesertMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containDesertMenu)
+                .toList();
+    }
+
+    private void validate(OrderMenu orderMenu) {
+        if (orderMenu.getOrderMenu().size() == MIN_ORDER_MENU) {
+            validateOnlyBeverage(orderMenu);
+        }
+
+        validateMaxQuantity(calculateTotalQuantity(orderMenu));
+    }
+
+    private void validateOnlyBeverage(OrderMenu orderMenu) {
+        MenuName menuName = orderMenu.getOrderMenu().keySet().stream()
+                .findFirst()
+                .orElseThrow();
+
+        String name = menuName.getName();
+        if (MenuInfo.findByMenuName(name).getCategory() == Category.BEVERAGE) {
+            throw new IllegalArgumentException(INVALID_MENU_ONLY_DRINK.getMessage());
+        }
+    }
+
+    private void validateMaxQuantity(int totalQuantity) {
+        if (totalQuantity > MAX_ORDER_QUANTITY) {
+            throw new IllegalArgumentException(INVALID_MAX_MENU_QUANTITY.getMessage());
+        }
+    }
+
+    private int calculateTotalQuantity(OrderMenu orderMenu) {
+        return orderMenu.getOrderMenu().values().stream()
+                .mapToInt(MenuQuantity::getQuantity)
+                .sum();
+    }
+}

리뷰: 이 코드의 흐름을 이해해 보고자 정말 열심히 노력했는데 실패했습니다...ㅠㅠ
주문 목록의 첫 번째 메뉴만 카테고리를 확인하는 것으로 해석을 했는데 이게 어떻게 음료만 주문한 경우를 판별할 수 있는 지 모르겠어요...
괜찮으시다면 편하실 때 설명 한번만 부탁드립니다..!
@@ -0,0 +1,30 @@
+package christmas.model.calendar;
+
+import static christmas.exception.ErrorType.INVALID_DAY_OUT_OF_RANGE;
+import static christmas.model.calendar.enums.CalendarDate.CHRISTMAS;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_MONTH;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_YEAR;
+import static christmas.model.calendar.enums.CalendarDate.FRIDAY;
+import static christmas.model.calendar.enums.CalendarDate.SATURDAY;
+import static christmas.model.calendar.enums.CalendarDate.START_DAY;
+import static christmas.model.calendar.enums.CalendarDate.SUNDAY;
+
+import java.time.LocalDate;
+
+public class ChristmasEventCalendar extends EventCalendar {
+
+    public ChristmasEventCalendar(int visitDay) {
+        super(visitDay);
+    }
+
+    protected void validateDayRange(int visitDay) {
+        if (visitDay < START_DAY.getNumber() || visitDay > CHRISTMAS.getNumber()) {
+            throw new IllegalArgumentException(INVALID_DAY_OUT_OF_RANGE.getMessage());
+        }
+    }
+
+    public int calculateVisitDayFromStart() {
+        int visitDay = getDayOfMonth();
+        return visitDay - START_DAY.getNumber();
+    }
+}

리뷰: 조건문이 길어진다면 메소드로 따로 빼두는 것도 좋을 것 같아요!
@@ -0,0 +1,20 @@
+package christmas.model.badge;
+
+import christmas.model.badge.enums.BadgeInfo;
+
+public class Badge {
+
+    private final BadgeInfo badgeInfo;
+
+    public Badge(int totalDiscountAmount) {
+        this.badgeInfo = selectBadge(totalDiscountAmount);
+    }
+
+    public String getBadgeName() {
+        return badgeInfo.getName();
+    }
+
+    private BadgeInfo selectBadge(int totalDiscountAmount) {
+        return BadgeInfo.findBadgeByPrice(totalDiscountAmount);
+    }
+}

리뷰: 저도 같은 의견입니다 ! 
`Badge` 클래스에서 이뤄지는 모든 로직은 `BadgeInfo`에서도 동일하기 수행할 수 있고
그렇게 한다면 클래스 명에 Info 를 추가하지 않아도 돼서 더욱 깔끔한 코드가 될 것 같아요 !
@@ -0,0 +1,54 @@
+package christmas.model.calendar;
+
+import static christmas.model.calendar.enums.CalendarDate.CHRISTMAS;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_MONTH;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_YEAR;
+import static christmas.model.calendar.enums.CalendarDate.FRIDAY;
+import static christmas.model.calendar.enums.CalendarDate.SATURDAY;
+import static christmas.model.calendar.enums.CalendarDate.SUNDAY;
+
+import java.time.LocalDate;
+
+public abstract class EventCalendar implements Calendar {
+
+    protected final LocalDate eventDate;
+
+    public EventCalendar(int visitDay) {
+        validate(visitDay);
+        this.eventDate = LocalDate.of(EVENT_YEAR.getNumber(), EVENT_MONTH.getNumber(), visitDay);
+    }
+
+    protected abstract void validateDayRange(int visitDay);
+
+    @Override
+    public boolean isWeekend() {
+        int visitDay = getDayOfWeek();
+        return visitDay == FRIDAY.getNumber() || visitDay == SATURDAY.getNumber();
+    }
+
+    @Override
+    public boolean isSpecialDay() {
+        return isChristmas() || isSunday();
+    }
+
+    @Override
+    public int getDayOfMonth() {
+        return eventDate.getDayOfMonth();
+    }
+
+    private void validate(int visitDay) {
+        validateDayRange(visitDay);
+    }
+
+    private boolean isChristmas() {
+        return getDayOfMonth() == CHRISTMAS.getNumber();
+    }
+
+    private boolean isSunday() {
+        return getDayOfWeek() == SUNDAY.getNumber();
+    }
+
+    private int getDayOfWeek() {
+        return eventDate.getDayOfWeek().getValue();
+    }
+}

리뷰: LocalDate를 활용하는 방법도 있었군요 ..!
더 다양항 활용을 할 수 있을 것 같아요!
@@ -0,0 +1,45 @@
+package christmas.model.discount;
+
+import static christmas.model.discount.enums.DiscountAmount.DESERT_DISCOUNT;
+import static christmas.model.discount.enums.DiscountAmount.NON_DISCOUNT;
+import static christmas.utils.Constants.MIN_ORDER_MENU;
+
+import christmas.model.calendar.Calendar;
+import christmas.model.order.MenuName;
+import christmas.model.order.OrderDetail;
+import java.util.List;
+
+public class WeekdaysDiscount implements Discount {
+
+    private final Calendar calendar;
+
+    private final OrderDetail orderDetail;
+
+    public WeekdaysDiscount(Calendar calendar, OrderDetail orderDetail) {
+        this.calendar = calendar;
+        this.orderDetail = orderDetail;
+    }
+
+    @Override
+    public int calculateDiscount() {
+        if (!calendar.isWeekend()) {
+            return desertDiscountPrice();
+        }
+        return NON_DISCOUNT.getDiscount();
+    }
+
+    private int desertDiscountPrice() {
+        List<MenuName> desertMenu = orderDetail.getDesertMenu();
+        int totalPrice = NON_DISCOUNT.getDiscount();
+        if (desertMenu.size() < MIN_ORDER_MENU) {
+            return totalPrice;
+        }
+
+        for (MenuName menuName : desertMenu) {
+            int quantityByMenu = orderDetail.getQuantityByMenu(menuName);
+            totalPrice += (quantityByMenu * DESERT_DISCOUNT.getDiscount());
+        }
+
+        return totalPrice;
+    }
+}

리뷰: `orderDetail.getDesertMenu()` 에서 디저트 메뉴가 없다면 빈 컬렉션이 반환되기 때문에
이 검증 로직이 없어도 괜찮지 않을까? 라는 생각이 들어요!
@@ -0,0 +1,45 @@
+package christmas.model.discount;
+
+import static christmas.model.discount.enums.DiscountAmount.MAIN_COURSE_DISCOUNT;
+import static christmas.model.discount.enums.DiscountAmount.NON_DISCOUNT;
+import static christmas.utils.Constants.MIN_ORDER_MENU;
+
+import christmas.model.calendar.Calendar;
+import christmas.model.order.MenuName;
+import christmas.model.order.OrderDetail;
+import java.util.List;
+
+public class WeekendDiscount implements Discount {
+
+    private final Calendar calendar;
+
+    private final OrderDetail orderDetail;
+
+    public WeekendDiscount(Calendar calendar, OrderDetail orderDetail) {
+        this.calendar = calendar;
+        this.orderDetail = orderDetail;
+    }
+
+    @Override
+    public int calculateDiscount() {
+        if (calendar.isWeekend()) {
+            return mainCourseDiscountPrice();
+        }
+        return NON_DISCOUNT.getDiscount();
+    }
+
+    private int mainCourseDiscountPrice() {
+        List<MenuName> mainMenu = orderDetail.getMainMenu();
+        int totalPrice = NON_DISCOUNT.getDiscount();
+        if (mainMenu.size() < MIN_ORDER_MENU) {
+            return totalPrice;
+        }
+
+        for (MenuName menuName : mainMenu) {
+            int quantityByMenu = orderDetail.getQuantityByMenu(menuName);
+            totalPrice += (quantityByMenu * MAIN_COURSE_DISCOUNT.getDiscount());
+        }
+
+        return totalPrice;
+    }
+}

리뷰: ~~~java
mainMenus.strem()
    .mapToInt(menu -> orderDetail.getQuantityByMenu(menuName))
    .sum()
~~~
과 같이 스트림을 활용해 보는 것도 좋아보여요!
@@ -0,0 +1,81 @@
+package christmas.model.order;
+
+import static christmas.exception.ErrorType.INVALID_MAX_MENU_QUANTITY;
+import static christmas.exception.ErrorType.INVALID_MENU_ONLY_DRINK;
+import static christmas.utils.Constants.MAX_ORDER_QUANTITY;
+import static christmas.utils.Constants.MIN_ORDER_MENU;
+
+import christmas.model.order.enums.Category;
+import christmas.model.order.enums.MenuInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class OrderDetail {
+
+    private final OrderMenu orderMenu;
+
+    public OrderDetail(OrderMenu orderMenu) {
+        validate(orderMenu);
+        this.orderMenu = orderMenu;
+    }
+
+    public Map<String, Integer> getOrderMenuName() {
+        Map<String, Integer> details = new HashMap<>();
+        for (Map.Entry<MenuName, MenuQuantity> entry : orderMenu.getOrderMenu().entrySet()) {
+            String menuName = entry.getKey().getName();
+            int quantity = entry.getValue().getQuantity();
+            details.put(menuName, quantity);
+        }
+
+        return Collections.unmodifiableMap(details);
+    }
+
+    public int getQuantityByMenu(MenuName menuName) {
+        return orderMenu.getMenuQuantity(menuName);
+    }
+
+    public List<MenuName> getMainMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containMainMenu)
+                .toList();
+    }
+
+    public List<MenuName> getDesertMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containDesertMenu)
+                .toList();
+    }
+
+    private void validate(OrderMenu orderMenu) {
+        if (orderMenu.getOrderMenu().size() == MIN_ORDER_MENU) {
+            validateOnlyBeverage(orderMenu);
+        }
+
+        validateMaxQuantity(calculateTotalQuantity(orderMenu));
+    }
+
+    private void validateOnlyBeverage(OrderMenu orderMenu) {
+        MenuName menuName = orderMenu.getOrderMenu().keySet().stream()
+                .findFirst()
+                .orElseThrow();
+
+        String name = menuName.getName();
+        if (MenuInfo.findByMenuName(name).getCategory() == Category.BEVERAGE) {
+            throw new IllegalArgumentException(INVALID_MENU_ONLY_DRINK.getMessage());
+        }
+    }
+
+    private void validateMaxQuantity(int totalQuantity) {
+        if (totalQuantity > MAX_ORDER_QUANTITY) {
+            throw new IllegalArgumentException(INVALID_MAX_MENU_QUANTITY.getMessage());
+        }
+    }
+
+    private int calculateTotalQuantity(OrderMenu orderMenu) {
+        return orderMenu.getOrderMenu().values().stream()
+                .mapToInt(MenuQuantity::getQuantity)
+                .sum();
+    }
+}

리뷰: 이미 `OrderMenu`가 일급 컬렉션의 역할을 하고 있는데 굳이 한번 더 감싸야 하나?? 라는 생각이 듭니다.. 
같은 역할을 `OrderMenu`가 수행해도 문맥상 전혀 이상하지 않을 것 같아요!
@@ -0,0 +1,54 @@
+package christmas.model.calendar;
+
+import static christmas.model.calendar.enums.CalendarDate.CHRISTMAS;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_MONTH;
+import static christmas.model.calendar.enums.CalendarDate.EVENT_YEAR;
+import static christmas.model.calendar.enums.CalendarDate.FRIDAY;
+import static christmas.model.calendar.enums.CalendarDate.SATURDAY;
+import static christmas.model.calendar.enums.CalendarDate.SUNDAY;
+
+import java.time.LocalDate;
+
+public abstract class EventCalendar implements Calendar {
+
+    protected final LocalDate eventDate;
+
+    public EventCalendar(int visitDay) {
+        validate(visitDay);
+        this.eventDate = LocalDate.of(EVENT_YEAR.getNumber(), EVENT_MONTH.getNumber(), visitDay);
+    }
+
+    protected abstract void validateDayRange(int visitDay);
+
+    @Override
+    public boolean isWeekend() {
+        int visitDay = getDayOfWeek();
+        return visitDay == FRIDAY.getNumber() || visitDay == SATURDAY.getNumber();
+    }
+
+    @Override
+    public boolean isSpecialDay() {
+        return isChristmas() || isSunday();
+    }
+
+    @Override
+    public int getDayOfMonth() {
+        return eventDate.getDayOfMonth();
+    }
+
+    private void validate(int visitDay) {
+        validateDayRange(visitDay);
+    }
+
+    private boolean isChristmas() {
+        return getDayOfMonth() == CHRISTMAS.getNumber();
+    }
+
+    private boolean isSunday() {
+        return getDayOfWeek() == SUNDAY.getNumber();
+    }
+
+    private int getDayOfWeek() {
+        return eventDate.getDayOfWeek().getValue();
+    }
+}

리뷰: 감사합니다 :)
@@ -0,0 +1,20 @@
+package christmas.model.badge;
+
+import christmas.model.badge.enums.BadgeInfo;
+
+public class Badge {
+
+    private final BadgeInfo badgeInfo;
+
+    public Badge(int totalDiscountAmount) {
+        this.badgeInfo = selectBadge(totalDiscountAmount);
+    }
+
+    public String getBadgeName() {
+        return badgeInfo.getName();
+    }
+
+    private BadgeInfo selectBadge(int totalDiscountAmount) {
+        return BadgeInfo.findBadgeByPrice(totalDiscountAmount);
+    }
+}

리뷰: 감사합니다. 객체에게 메세지를 던져서 캡슐화 시키려고 의도했었는데, 상당히 불필요하다고 생각되네요 ㅎㅎ
@@ -0,0 +1,15 @@
+package christmas.model.order.enums;
+
+public enum Category {
+
+    APPETIZER("에피타이저"),
+    MAIN_COURSE("메인"),
+    DESSERT("디저트"),
+    BEVERAGE("음료");
+
+    private final String category;
+
+    Category(String category) {
+        this.category = category;
+    }
+}

리뷰: 네 맞습니다!
@@ -0,0 +1,81 @@
+package christmas.model.order;
+
+import static christmas.exception.ErrorType.INVALID_MAX_MENU_QUANTITY;
+import static christmas.exception.ErrorType.INVALID_MENU_ONLY_DRINK;
+import static christmas.utils.Constants.MAX_ORDER_QUANTITY;
+import static christmas.utils.Constants.MIN_ORDER_MENU;
+
+import christmas.model.order.enums.Category;
+import christmas.model.order.enums.MenuInfo;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class OrderDetail {
+
+    private final OrderMenu orderMenu;
+
+    public OrderDetail(OrderMenu orderMenu) {
+        validate(orderMenu);
+        this.orderMenu = orderMenu;
+    }
+
+    public Map<String, Integer> getOrderMenuName() {
+        Map<String, Integer> details = new HashMap<>();
+        for (Map.Entry<MenuName, MenuQuantity> entry : orderMenu.getOrderMenu().entrySet()) {
+            String menuName = entry.getKey().getName();
+            int quantity = entry.getValue().getQuantity();
+            details.put(menuName, quantity);
+        }
+
+        return Collections.unmodifiableMap(details);
+    }
+
+    public int getQuantityByMenu(MenuName menuName) {
+        return orderMenu.getMenuQuantity(menuName);
+    }
+
+    public List<MenuName> getMainMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containMainMenu)
+                .toList();
+    }
+
+    public List<MenuName> getDesertMenu() {
+        return orderMenu.getOrderMenu().keySet().stream()
+                .filter(orderMenu::containDesertMenu)
+                .toList();
+    }
+
+    private void validate(OrderMenu orderMenu) {
+        if (orderMenu.getOrderMenu().size() == MIN_ORDER_MENU) {
+            validateOnlyBeverage(orderMenu);
+        }
+
+        validateMaxQuantity(calculateTotalQuantity(orderMenu));
+    }
+
+    private void validateOnlyBeverage(OrderMenu orderMenu) {
+        MenuName menuName = orderMenu.getOrderMenu().keySet().stream()
+                .findFirst()
+                .orElseThrow();
+
+        String name = menuName.getName();
+        if (MenuInfo.findByMenuName(name).getCategory() == Category.BEVERAGE) {
+            throw new IllegalArgumentException(INVALID_MENU_ONLY_DRINK.getMessage());
+        }
+    }
+
+    private void validateMaxQuantity(int totalQuantity) {
+        if (totalQuantity > MAX_ORDER_QUANTITY) {
+            throw new IllegalArgumentException(INVALID_MAX_MENU_QUANTITY.getMessage());
+        }
+    }
+
+    private int calculateTotalQuantity(OrderMenu orderMenu) {
+        return orderMenu.getOrderMenu().values().stream()
+                .mapToInt(MenuQuantity::getQuantity)
+                .sum();
+    }
+}

리뷰: 상단에  validate를 보시면 이해하실 수 있을거에요..!
@@ -0,0 +1,18 @@
+package subway.config;
+
+import lombok.extern.slf4j.*;
+import org.springframework.http.*;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    @ExceptionHandler(RuntimeException.class)
+    public ResponseEntity<ErrorResponse> runtimeException(final RuntimeException e) {
+
+        log.error("error: ", e);
+        return ResponseEntity.badRequest()
+                .body(new ErrorResponse(e.getMessage()));
+    }
+}

리뷰: 에러 공통 처리를 잘 해주셨네요! 😊

예외종류에 따라 로깅레벨을 적절하게 분리해서 로그를 남기는 것도 좋을 거 같은데 어떻게 생각하시나요?

logging level 관련해서는 아래 내용을 참고해 주시면 감사하겠습니다.

예) log.error("Unexpected exception occurred: {}", e.getMessage(), e);

○ DEBUG : 개발단계에서부터 활성화.프로세스의처리순서/흐름을분석하는데 도움이 되는 정보 등
○ INFO : 디버깅정보외에 프로세스설정 / 기동에 관련한 정보 등
○ WARN : 오류상황은 아니지만, 추후확인이 필요한 정보 등
○ ERROR : 오류가 발생한상황 .즉시 대응이 필요할수있음
○ FATAL : 매우 심각한상황. 즉시 대응이 필요함
@@ -1,13 +1,13 @@
 package subway.line;
 
 import lombok.*;
+import subway.*;
+import subway.line.section.*;
 
 import javax.persistence.*;
 
 @Entity
 @NoArgsConstructor(access = AccessLevel.PROTECTED)
-@AllArgsConstructor(access = AccessLevel.PRIVATE)
-@Builder
 @Getter
 public class Line {
 
@@ -21,13 +21,27 @@ public class Line {
     private String color;
 
     @Embedded
-    @Builder.Default
-    private LineStations lineStations = new LineStations();
+    private Sections sections;
+
+    @Builder
+    private Line(
+            final Long id,
+            final String name,
+            final String color,
+            final Section section
+    ) {
+
+        section.changeLine(this);
+        this.id = id;
+        this.name = name;
+        this.color = color;
+        this.sections = new Sections(section);
+    }
 
-    public Line addLineStation(final LineStation lineStation) {
+    public Line addSection(final Section section) {
 
-        this.lineStations.add(lineStation);
-        lineStation.changeLine(this);
+        this.sections.add(section);
+        section.changeLine(this);
         return this;
     }
 
@@ -37,4 +51,10 @@ public Line change(final String name, final String color) {
         return this;
     }
 
+    public Line removeSection(final Station downStation) {
+
+        this.sections.remove(downStation);
+        return this;
+    }
+
 }

리뷰: `@Embedded 을 이용해 도메인 로직을 잘 분리해 주셨군요! 👍
@@ -0,0 +1,49 @@
+package subway.line.section;
+
+import lombok.*;
+import org.springframework.stereotype.*;
+import org.springframework.transaction.annotation.*;
+import subway.*;
+import subway.line.*;
+
+@Service
+@Transactional
+@RequiredArgsConstructor
+public class SectionService {
+
+    private final StationService stationService;
+    private final LineService lineService;
+
+    public void addSection(final Long lineId, final SectionAddRequest request) {
+
+        final var line = lineService.getById(lineId);
+
+        final var upStation = stationService.getById(request.getUpStationId());
+        final var downStation = stationService.getById(request.getDownStationId());
+
+        line.addSection(createSection(request, line, upStation, downStation));
+    }
+
+    private static Section createSection(
+            final SectionAddRequest request,
+            final Line line,
+            final Station upStationId,
+            final Station downStationId
+    ) {
+
+        return Section.builder()
+                .line(line)
+                .upStation(upStationId)
+                .downStation(downStationId)
+                .distance(request.getDistance())
+                .build();
+    }
+
+    public void removeSection(final Long lineId, final Long stationId) {
+
+        final var line = lineService.getById(lineId);
+        final var station = stationService.getById(stationId);
+
+        line.removeSection(station);
+    }
+}

리뷰: 해당 함수는 SectionService 에서만 사용하는 것으로 보여지는데 static 으로 선언한 이유가 있을까요? 😊
@@ -0,0 +1,81 @@
+package subway.line.section;
+
+import lombok.*;
+import subway.*;
+
+import javax.persistence.*;
+import java.util.*;
+
+@Embeddable
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class Sections {
+
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "line", cascade = CascadeType.ALL, orphanRemoval = true)
+    private List<Section> values = new ArrayList<>();
+
+    public Sections(final Section section) {
+        final ArrayList<Section> sections = new ArrayList<>();
+        sections.add(section);
+        this.values = sections;
+    }
+
+    public Sections add(final Section section) {
+
+        validationLastStation(section.getUpStation());
+
+        if (this.anyMatchStation(section.getDownStation())) {
+            throw new DuplicateSectionStationException();
+        }
+
+        this.values.add(section);
+        return this;
+    }
+
+    private void validationLastStation(final Station section) {
+        if (!this.isLastStation(section)) {
+            throw new NotLastDownStationException();
+        }
+    }
+
+    public Sections remove(final Station downStation) {
+        validationLastStation(downStation);
+        if(isOnlyOne()) {
+            throw new OnlyOneSectionException();
+        }
+
+        this.values.removeIf(section -> section.isDownStation(downStation));
+        return this;
+    }
+
+    private boolean isOnlyOne() {
+        return this.values.size() == 1;
+    }
+
+    public List<Section> getValues() {
+
+        return List.copyOf(this.values);
+    }
+
+    public boolean isLastStation(final Station station) {
+
+        return getLastSection()
+                .map(section -> section.isDownStation(station))
+                .orElse(false);
+    }
+
+    private Optional<Section> getLastSection() {
+        if(this.values.isEmpty()) {
+            return Optional.empty();
+        }
+        return Optional.of(this.values.get(lastIndex()));
+    }
+
+    private int lastIndex() {
+        return this.values.size() - 1;
+    }
+
+    public boolean anyMatchStation(final Station station) {
+        return this.values.stream()
+                .anyMatch(section -> section.anyMatchStation(station));
+    }
+}

리뷰: 매개변수 타입은 Station 인데 변수 명은 section 이여서 혼동이 있어 보여요! 😊