ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,36 @@
+package christmas.back.application.usecase;
+
+import christmas.back.application.service.ClientService;
+import christmas.back.application.service.MenuOrderService;
+import christmas.back.domain.event.config.BaseEvent;
+import christmas.back.domain.event.config.EventConfig;
+import christmas.back.domain.event.config.EventType;
+import christmas.back.domain.order.MenuOrders;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+public class CheckEventAndUpdateClientPayment {
+    private final MenuOrderService menuOrderService;
+    private final ClientService clientService;
+    private final List<BaseEvent> events;
+
+    public CheckEventAndUpdateClientPayment(ClientService clientService,MenuOrderService menuOrderService) {
+        this.events = EventConfig.configEvent();
+        this.menuOrderService = menuOrderService;
+        this.clientService = clientService;
+    }
+    public List<Map<EventType,Integer>> execute(Long clientId) {
+        var client = clientService.findClientById(clientId);
+        List<Map<EventType,Integer>> output  = new ArrayList<>();
+        MenuOrders menuOrders = menuOrderService.findMenuOrdersById(client.getMenuOrdersId());
+        events.forEach(event ->{
+            if(event.canGetEvent(client,menuOrders)) {
+                output.add(event.getEventBenefit(client,menuOrders));
+                event.updateClientBenefit(client,menuOrders);
+            }
+        });
+        return output;
+    }
+}

리뷰: 키-값의 한 쌍씩을 리스트 형태로 구성하고자 하신거라면 물론 Map도 물론 좋지만 Entry도 좋은 선택지일 거라고 생각합니다. 저도 일급객체만을 사용해서 여러 키-값을 어떻게 반환해줄 지 고민했었는데 List에 Map을 통째로 넣는 것은 낭비라는 생각이 들더라구요
@@ -0,0 +1,21 @@
+package christmas.back.application.service;
+
+import christmas.back.domain.order.MenuOrders;
+import christmas.back.domain.order.MenuOrdersRepository;
+import christmas.back.infrastructure.repository.MenuOrdersRepositoryImpl;
+
+public class MenuOrderService {
+    private final MenuOrdersRepository menuOrdersRepository;
+
+    public MenuOrderService() {
+        this.menuOrdersRepository = new MenuOrdersRepositoryImpl();
+    }
+
+    public MenuOrders saveOrders(MenuOrders menuOrders) {
+        return menuOrdersRepository.save(menuOrders);
+    }
+
+    public MenuOrders findMenuOrdersById(Long menuOrdersId) {
+        return menuOrdersRepository.findById(menuOrdersId);
+    }
+}

리뷰: 의존성을 생각하여 레포지토리의 구현체는 서비스에서 생성하는 것으로 생각했습니다. (+ 토스 개발 영상 중 계층간의 이동을 뛰어 넘지 않는다라는 룰이 생각났습니다)

 그래도 컴포넌트 스캔을 만들어서 DI 로 구현했으면 더 완벽했을 것 같습니다
@@ -1,7 +1,19 @@
 package christmas;
 
+import christmas.back.application.service.ClientService;
+import christmas.back.application.service.MenuOrderService;
+import christmas.front.controller.IOController;
+import christmas.back.controller.PlannerController;
+import christmas.front.view.InputView;
+import christmas.front.view.OutputView;
+
 public class Application {
     public static void main(String[] args) {
-        // TODO: 프로그램 구현
+        var clientService = new ClientService();
+        var menuOrderService = new MenuOrderService();
+        var ioController = new IOController(new InputView(),new OutputView());
+        PlannerController plannerController = new PlannerController(ioController,clientService,menuOrderService);
+        plannerController.startPlanner();
+        plannerController.showOrderResult();
     }
 }

리뷰: (일단 질문을 받아 드는 생각을 적었지만 내일까지 다시한번 생각해보겠습니다ㅎㅎ)

Front controller 의 역할을 하는 디스패처 서블릿이 있다라는 것을 생각하여 io 컨트롤러의 경우 Front 의 코드라고 생각을 하였습니다.  메인이 될 어플리케이션 로직을 담당하는 컨트롤러인 PlannerController 에서 도메인 모델을 다루지 않는 IO 컨트롤러를 호출해도 순환은 안할것 같다라고 생각을 했습니다.(클라스 이름을 다시한번 고민해보겠습니다 !!)

서비스의 경우 관리하는 도메인의 영역이 커지면 인터페이스를 통하여 서로 참조하는 방식으로 개발을 할것이라고 생각합니다.

순환참조의 오류를 가질수 있지만 , 하나의 서비스에서 다른 도메인들의 레포지토리를 호출하게 되면 도메인간의 분리가 더 어려울 것 같다라고 생각합니다. 

 계층간의 분리 즉 컨트롤러 , 서비스 , 도메인 모델 , 레포지토리의 경계를 나누는 것은 동의하는 입장입니다.

도메인간의 서비스 계층은 같은 계층으로 이해를 하여 단방향으로 호출하는 상황은 괜찮다라고 생각합니다.

실제 restapi 를 지원하는 어플리케이션의 경우  언급해 주신 것처럼 서로 컨트롤러 간에 의존하지 않고 개발을 할것 같습니다.
@@ -0,0 +1,47 @@
+package christmas.back.application.service;
+
+import christmas.back.domain.event.gift.GiftEvent;
+import christmas.back.domain.user.ClientRepository;
+import christmas.back.domain.user.model.Client;
+import christmas.back.infrastructure.repository.ClientRepositoryImpl;
+
+public class ClientService {
+    private final ClientRepository clientRepository;
+
+    public ClientService() {
+        this.clientRepository = new ClientRepositoryImpl();
+    }
+
+    public Client saveClient(Client clientInfo) {
+        Client client = new Client(clientInfo);
+        return clientRepository.save(client);
+    }
+
+    public Client findClientById(Long id) {
+        return clientRepository.findById(id);
+    }
+
+    public Integer getTotalAmountBeforeDiscount(Long clientId) {
+        return findClientById(clientId).getPayment().getTotalPaymentBeforeDiscount();
+    }
+
+    public String getGiftEventMenu(Long clientId) {
+        return GiftEvent.getGiftMenu(findClientById(clientId));
+    }
+
+    public Integer getTotalDiscountAmount(Long clientId) {
+        return findClientById(clientId).getPayment().getTotalDiscountMoney();
+    }
+
+    public Integer getAfterDiscount(Long clientId) {
+        return findClientById(clientId).getPayment().getAfterDiscount();
+    }
+
+    public String getBadgeContent(Long clientId) {
+        return findClientById(clientId).getBadgeContent();
+    }
+
+    public void updateBadge(Long clientId) {
+        findClientById(clientId).applyBadge();
+    }
+}

리뷰: 기회가되시면 유투브 우아한테크 세미나의 의존성과 관련된 영상을 추천 드리고 싶습니다 .
워낙 유명한 영상이라 이미 보셨을 수 있지만 ,  단순하게 유지보수의 측면의 도메인을 분리하는 설계의 중요성뿐만 아니라 데이터베이스와의 연관의 대한 설명도 포함하는 내용이 있습니다 :)
@@ -0,0 +1,36 @@
+package christmas.back.application.usecase;
+
+import christmas.back.application.service.ClientService;
+import christmas.back.application.service.MenuOrderService;
+import christmas.back.domain.event.config.BaseEvent;
+import christmas.back.domain.event.config.EventConfig;
+import christmas.back.domain.event.config.EventType;
+import christmas.back.domain.order.MenuOrders;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+public class CheckEventAndUpdateClientPayment {
+    private final MenuOrderService menuOrderService;
+    private final ClientService clientService;
+    private final List<BaseEvent> events;
+
+    public CheckEventAndUpdateClientPayment(ClientService clientService,MenuOrderService menuOrderService) {
+        this.events = EventConfig.configEvent();
+        this.menuOrderService = menuOrderService;
+        this.clientService = clientService;
+    }
+    public List<Map<EventType,Integer>> execute(Long clientId) {
+        var client = clientService.findClientById(clientId);
+        List<Map<EventType,Integer>> output  = new ArrayList<>();
+        MenuOrders menuOrders = menuOrderService.findMenuOrdersById(client.getMenuOrdersId());
+        events.forEach(event ->{
+            if(event.canGetEvent(client,menuOrders)) {
+                output.add(event.getEventBenefit(client,menuOrders));
+                event.updateClientBenefit(client,menuOrders);
+            }
+        });
+        return output;
+    }
+}

리뷰: 마지막의 자료구조의 대하여 고민을 했던 부분인데 피드백 정말 감사합니다!
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: ```javascript
import ClickMeButton from './components/ClickMeButton';
import NumberButtons from './components/NumberButtons';
```

이렇게 확장자 없이 작성해 보세요
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: handler함수의 이름과 컴포넌트의 속성 이름을 똑같이 맞춰주신 것 같아요.

핸들러 함수에 `handle*`이라고 이름을 붙이는 이유는 특정 이벤트가 발생했을 때 그 이벤트를 처리하는 함수이기 때문입니다.

```jsx
function handleClick() {
  alert('버튼이 클릭됐어요!');
}

<Button onClick={handleClick} />
```

위의 예제를 보면 보면 `Click 했을 때 handleClick이 처리한다` 라고 읽을 수 있습니다. 그래서 이벤트 처리 함수를 컴포넌트로 전달할 때는 on으로 시작하는 이름으로 전달합니다.
@@ -0,0 +1,9 @@
+import React from 'react';
+
+export default function ClickMeButton({ counterNumber, onClick, number }) {
+  return (
+    <button type="button" onClick={() => onClick({ number })}>
+      Click me ({counterNumber})
+    </button>
+  );
+}

리뷰: 버튼을 클릭했을 때 1씩 증가해서 `{ number: 1}`로 전달하고 있네요. 만약에 1씩 증가하는 것이 아니라 2씩 증가하도록 변경한다면 이 컴포넌트를 변경해줘야겠습니다.

만약 이러한 로직을 외부에서 변경할 수 있도록 하려면 어떻게 해야 할까요
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: <img width="406" alt="스크린샷 2023-05-12 오후 7 00 47" src="https://github.com/CodeSoom/react-week2-assignment-1/assets/103479322/dc146c47-9a01-4296-8d1d-357ee875bf9f">
확장자를 지워도 똑같이 문제가 발생합니다!
@@ -0,0 +1,9 @@
+import React from 'react';
+
+export default function ClickMeButton({ counterNumber, onClick, number }) {
+  return (
+    <button type="button" onClick={() => onClick({ number })}>
+      Click me ({counterNumber})
+    </button>
+  );
+}

리뷰: `      <ClickMeButton
        counterNumber={counterNumber}
        onClick={handlerClickButton}
        whatNumberToAdd={1}
      />`

`  return (
    <button type="button" onClick={() => onClick({ number: whatNumberToAdd })}>
      Click me ({counterNumber})
    </button>
  );`

이런식으로 컴포넌트 생성할 때 whatNumberToAdd라는 값도 props로 넘겨주고
실제 click할 때는 해당 props의 값을 넘겨주는 형태로 해봤습니다!
이렇게 되면 자식 컴포넌트에서 들어가는 변수는 하나도 없이 전달받은 값만 보여주고,
모두 부모 컴포넌트에서 핸들링하기 때문에 관심사가 분리된 코드라고 생각합니다! 🙂
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: 핸들러 함수에 handle*이라고 이름을 붙이는 이유는 특정 이벤트가 발생했을 때 그 이벤트를 처리하는 함수라는 맥락은 이해가 되었고, 그래서 on으로 시작하는 이름으로 전달하는 의미도 이해는 되었습니다!

그런데 위의 경우에서 자식요소에서 handleClick이라는 함수를 쓸 때는 아래와 같이 사용하게 될 것 같은데요!
```
<button onClick={()=>onClick()} ></button>
```
이렇게 될 경우에는 onClick이라는 것을 onClick으로 전달받은 함수를 실행한다는 의미인데 
제가 봤을 때는 onClick을 했을 때 onClick함수를 실행한다는게 오히려 어색한 것 같다는 생각도 들어서요🥲

그럼에도 on으로 시작하는 이름으로 전달해주는 것이다라는 의미를 강조하는 목적이 더 크니 이렇게 쓰는게 더 나은 방식이라고 이해하면 될까요?
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: https://baeharam.netlify.app/posts/lint/Lint-ESLint-+-Prettier-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

```
"rules": {
  "react/jsx-filename-extension": ["warn", { "extensions": [".js", ".jsx"] }]
}
```
eslint-plugin-react 설치 여부를 체크하고 위의 룰을 추가로 기입해주면 해결된다는 사례도 있어서
해봤는데 이 역시도 안되네요 🥺
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: 해당 컴포넌트에서 onClick이라는 이름으로 함수를 실행하니 어색하게 느껴질 수 있겠네요. 사용하는 컴포넌트에서 사용하는게 어색하게 느껴지신다면 이름을 바꿔서 사용할 수 있긴 하겠네요.

```javascript
const ButtonComponent = ({ onClick: handleClick }) => {
  return (
    <button onClick={handleClick}></button>
  );
};
```

저는 컴포넌트를 쓰는 입장에서 이해하기 좋은 이름이어야 한다는 생각때문에 그랬던 것 같습니다 ㅎㅎ
@@ -0,0 +1,9 @@
+import React from 'react';
+
+export default function ClickMeButton({ counterNumber, onClick, number }) {
+  return (
+    <button type="button" onClick={() => onClick({ number })}>
+      Click me ({counterNumber})
+    </button>
+  );
+}

리뷰: 별도의 속성을 넣어서 값을 몇씩 더할지 변경할 수 있겠네요 ㅎㅎ 좋습니다. 저는 핸들러 함수를 외부에서 전달하고 컴포넌트에서는 단순히 실행만 하도록 하는 것을 생각해 보았어요

```javascript
const handleClickMeButton = () => {
  setCounerNumber(counterNumber + 10);
}

return (
  <ClickMeButton>
    counterNumber={counterNumber}
    onClick={handleClickMeButton}>
  </ClickMeButton>
)

//

export default function ClickMeButton({ counterNumber, onClick }) {
  return (
    <button type="button" onClick={onClick}>
      Click me (
      {counterNumber}
      )
    </button>
  );
}
```
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: 아하! 제안해주신 것도 좋은 방법인것같아요! 
역시 이름 짓는 건 참 어려운일이네요 ㅠㅠ
감사합니다 :) ㅎㅎ
@@ -0,0 +1,9 @@
+import React from 'react';
+
+export default function ClickMeButton({ counterNumber, onClick, number }) {
+  return (
+    <button type="button" onClick={() => onClick({ number })}>
+      Click me ({counterNumber})
+    </button>
+  );
+}

리뷰: 아하! 좋은 것 같아요 :)

저 같은 경우에는 handleClickButton이라는 핸들러함수를 clickmebutton 컴포넌트와 numberbutton에 공통으로 사용되는 함수로 두고 싶었어요!
이유는 둘 다 특정 값을 더해서 뱉어주는 역할을 하기 때문에 굳이 각각의 핸들러 함수를 만들고 싶지 않았습니닷!
그래서 같은 핸들러 함수를 쓰고, 더해주는 값만 사용되는 컴포넌트의 인자로 넣어주면 좋지 않을까 생각해서 사용했습니다ㅎㅎ

피드백해주셔서 감사해요 :)
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: 속성명을 아주 자세히 작성해 주셨네요. 그러다보니 컴포넌트가 어떤 일을 하는지를 변수명에도 드러났네요. 주어진 값으로 더한다는 사실을 바로 알아서 좋을 수도 있지만 이건 단점이 될수도 있습니다. 우리가 이 컴포넌트에게 맡기는 것은 단순한 값이고 이 값으로 무엇을 할지는 이 컴포넌트만 알고 있어야 합니다. 이게 캡슐화입니다.

조금 억지일수도 있지만 만약 주어진 값을 제곱으로 더하기로 했다고 합시다. 그러면 이 속성의 이름도 바뀌어야 할거예요.
@@ -0,0 +1,24 @@
+import React, { useState } from 'react';
+import ClickMeButton from './components/ClickMeButton';
+import NumberButtons from './components/NumberButtons';
+
+export default function App() {
+  const [counterNumber, setCounterNumber] = useState(0);
+
+  function handlerClickButton({ number }) {
+    setCounterNumber(counterNumber + number);
+  }
+
+  return (
+    <div>
+      <p>Counter</p>
+      <ClickMeButton
+        counterNumber={counterNumber}
+        onClick={handlerClickButton}
+        number={1}
+      />
+      <br />
+      <NumberButtons onClick={handlerClickButton} />
+    </div>
+  );
+}

리뷰: 감사합니다 :) 덕분에 추상화를 항상 유념하면서 코드를 짜게 되는 것 같아요!
속성명을 number로 변경해서 해당 컴포넌트에서만 명확한 역할을 알게 수정했습니다!
@@ -0,0 +1,58 @@
+package lotto.domain;
+
+import static lotto.global.Error.DUPLICATED;
+import static lotto.global.Error.INVALID_SIZE;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Lotto {
+    private final List<Integer> numbers;
+
+    public Lotto(List<Integer> numbers) {
+        validateSize(numbers);
+        validateDuplicated(numbers);
+        validateNumberRange(numbers);
+        this.numbers = numbers;
+    }
+
+    private void validateSize(List<Integer> numbers) {
+        if (numbers.size() != 6) {
+            throw new IllegalArgumentException(INVALID_SIZE.getMessage());
+        }
+    }
+
+    private void validateDuplicated(List<Integer> numbers) {
+        if (numbers.stream()
+                .distinct().count() != numbers.size()) {
+            throw new IllegalArgumentException(DUPLICATED.getMessage());
+        }
+    }
+
+    private void validateNumberRange(List<Integer> numbers) {
+        numbers.forEach(Number::new);
+    }
+
+    // TODO: 추가 기능 구현
+    public WinningResult checkWinningResult(WinningLotto winningLotto) {
+        int winningCount = checkWinningCount(winningLotto);
+        boolean hasBonusNumber = hasBonusNumber(winningLotto);
+        return new WinningResult(winningCount, hasBonusNumber);
+    }
+
+    private int checkWinningCount(WinningLotto winningLotto) {
+        return (int) numbers.stream()
+                .filter(number -> winningLotto
+                        .getWinningNumbers()
+                        .contains(number))
+                .count();
+    }
+
+    private boolean hasBonusNumber(WinningLotto winningLotto) {
+        return numbers.contains(winningLotto.getBonusNumber());
+    }
+
+    public List<Integer> getNumbers() {
+        return Collections.unmodifiableList(numbers);
+    }
+}

리뷰: 매직 넘버 따로 관리 해주면 좋을 것 같습니다.
@@ -0,0 +1,58 @@
+package lotto.domain;
+
+import static lotto.global.Error.DUPLICATED;
+import static lotto.global.Error.INVALID_SIZE;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Lotto {
+    private final List<Integer> numbers;
+
+    public Lotto(List<Integer> numbers) {
+        validateSize(numbers);
+        validateDuplicated(numbers);
+        validateNumberRange(numbers);
+        this.numbers = numbers;
+    }
+
+    private void validateSize(List<Integer> numbers) {
+        if (numbers.size() != 6) {
+            throw new IllegalArgumentException(INVALID_SIZE.getMessage());
+        }
+    }
+
+    private void validateDuplicated(List<Integer> numbers) {
+        if (numbers.stream()
+                .distinct().count() != numbers.size()) {
+            throw new IllegalArgumentException(DUPLICATED.getMessage());
+        }
+    }
+
+    private void validateNumberRange(List<Integer> numbers) {
+        numbers.forEach(Number::new);
+    }
+
+    // TODO: 추가 기능 구현
+    public WinningResult checkWinningResult(WinningLotto winningLotto) {
+        int winningCount = checkWinningCount(winningLotto);
+        boolean hasBonusNumber = hasBonusNumber(winningLotto);
+        return new WinningResult(winningCount, hasBonusNumber);
+    }
+
+    private int checkWinningCount(WinningLotto winningLotto) {
+        return (int) numbers.stream()
+                .filter(number -> winningLotto
+                        .getWinningNumbers()
+                        .contains(number))
+                .count();
+    }
+
+    private boolean hasBonusNumber(WinningLotto winningLotto) {
+        return numbers.contains(winningLotto.getBonusNumber());
+    }
+
+    public List<Integer> getNumbers() {
+        return Collections.unmodifiableList(numbers);
+    }
+}

리뷰: 해당 부분을 Intstream으로 사용이 가능하지 않을까요????
@@ -0,0 +1,30 @@
+package lotto.domain;
+
+import java.util.Collections;
+import java.util.List;
+import lotto.global.Error;
+
+public class WinningLotto {
+    private final List<Integer> winningNumbers;
+    private final int bonusNumber;
+
+    public WinningLotto(List<Integer> winningNumbers, int bonusNumber) {
+        validateBonusNumber(winningNumbers, bonusNumber);
+        this.winningNumbers = winningNumbers;
+        this.bonusNumber = bonusNumber;
+    }
+
+    private void validateBonusNumber(List<Integer> winningNumbers, int bonusNumber) {
+        if (winningNumbers.contains(bonusNumber)) {
+            throw new IllegalArgumentException(Error.INVALID_BONUS_NUMBER.getMessage());
+        }
+    }
+
+    public List<Integer> getWinningNumbers() {
+        return Collections.unmodifiableList(winningNumbers);
+    }
+
+    public int getBonusNumber() {
+        return bonusNumber;
+    }
+}

리뷰: 당첨 번호 로또를 따로 두셨네요. 좋은 방법인 것 같아요. 저는 똑같은 로또라고 꼭 같이 사용해야 한다고만 생각했었는데. 이러면 보너스 번호 확인을 보다 쉽게 할 수 있을 것 같아서 좋은 것 같습니다.
@@ -0,0 +1,38 @@
+package lotto.domain;
+
+import static lotto.domain.Rank.NONE;
+
+import java.util.Arrays;
+
+public class WinningResult {
+    private static final int SECOND_OR_THIRD = 5;
+    private final int winningCount;
+    private final boolean hasBonusNumber;
+
+    public WinningResult(int winningCount, boolean matchingBonusNumber) {
+        this.winningCount = winningCount;
+        this.hasBonusNumber = matchingBonusNumber;
+    }
+
+    public Rank toRank() {
+        if (winningCount == SECOND_OR_THIRD) {
+            return Arrays.stream(Rank.values())
+                    .filter(rank -> rank.getWinningCount() == winningCount)
+                    .filter(rank -> rank.hasBonusNumber() == hasBonusNumber)
+                    .findAny()
+                    .orElse(NONE);
+        }
+        return Arrays.stream(Rank.values())
+                .filter(rank -> rank.getWinningCount() == winningCount)
+                .findAny()
+                .orElse(NONE);
+    }
+
+    public int getWinningCount() {
+        return winningCount;
+    }
+
+    public boolean hasBonusNumber() {
+        return hasBonusNumber;
+    }
+}

리뷰: enum이 선언된 순서대로 인덱스가 정해지는 걸로 알고있습니다. 이를 이용해서 2등, 3등의 당첨 번호 갯수를 filter한 후 다음 filter로 보너스 여부 체크 하고 이후 나머지 랭크를 체크하는 방법을 쓰면 해당 부분의 코드를 조금 줄일 수 있지 않을까요??? 상추님의 생각이 궁금합니다^^