ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,79 @@
+package lotto.model;
+
+import lotto.model.constants.LottoPrize;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+import static lotto.constants.ErrorMessage.DUPLICATION;
+import static lotto.constants.ErrorMessage.SIXNUMBER;
+import static lotto.model.constants.LottoPrize.*;
+public class Lotto {
+    private final List<Integer> numbers;
+
+    public Lotto(List<Integer> numbers) {
+        validate(numbers);
+        duplicate(numbers);
+        this.numbers = numbers;
+    }
+
+    private void duplicate(List<Integer> numbers) {
+                List<Integer> duplication = numbers.stream()
+                        .distinct()
+                        .toList();
+                if (duplication.size() != numbers.size()) {
+                    throw new IllegalArgumentException(DUPLICATION.getMessage());
+                }
+    }
+
+    private void validate(List<Integer> numbers) {
+                if (numbers.size() != 6) {
+                    throw new IllegalArgumentException(SIXNUMBER.getMessage());
+        }
+    }
+    public void checkSame(Integer bonusNumber, List<List<Integer>> lottoNumber) {
+        bonusDuplication(bonusNumber);
+        for (List<Integer> integers : lottoNumber) {
+            List<Integer> Result = integers.stream()
+                    .filter(i -> this.numbers.stream().anyMatch(Predicate.isEqual(i)))
+                    .toList();
+            long bonusResult = integers.stream()
+                    .filter(bonusNumber::equals).count();
+            CheckPrize(Result.size(), bonusResult).addWinCount();
+
+        }
+    }
+
+    private void bonusDuplication(Integer bonusNumber) {
+        List<Integer> Result = this.numbers.stream()
+                .filter(i-> !Objects.equals(i, bonusNumber))
+                .toList();
+        if(Result.size()!=6){
+            throw new IllegalArgumentException(DUPLICATION.getMessage());
+        }
+
+    }
+
+    public LottoPrize CheckPrize(int result, long bonusResult){
+        if(result==6){
+            return FIRST_PRIZE;
+        }
+        if(result==5&&bonusResult==1){
+            return SECOND_PRIZE;
+        }
+        if(result==5&&bonusResult==0){
+            return THIRD_PRIZE;
+        }
+        if(result==4){
+            return FOURTH_PRIZE;
+        }
+        if(result==3){
+            return FIFTH_PRIZE;
+        }
+        if(result<3){
+            return LOOSE;
+        }
+        throw new IllegalArgumentException("존재 하지 않는 순위입니다.");
+    }
+}

리뷰: ```suggestion
                    .filter(i -> this.numbers
                    .stream()
                    .anyMatch(Predicate.isEqual(i)))
```
다음과 같이 개행처리 해주시는게 가독성에 좋아보입니다!
@@ -0,0 +1,79 @@
+package lotto.model;
+
+import lotto.model.constants.LottoPrize;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+import static lotto.constants.ErrorMessage.DUPLICATION;
+import static lotto.constants.ErrorMessage.SIXNUMBER;
+import static lotto.model.constants.LottoPrize.*;
+public class Lotto {
+    private final List<Integer> numbers;
+
+    public Lotto(List<Integer> numbers) {
+        validate(numbers);
+        duplicate(numbers);
+        this.numbers = numbers;
+    }
+
+    private void duplicate(List<Integer> numbers) {
+                List<Integer> duplication = numbers.stream()
+                        .distinct()
+                        .toList();
+                if (duplication.size() != numbers.size()) {
+                    throw new IllegalArgumentException(DUPLICATION.getMessage());
+                }
+    }
+
+    private void validate(List<Integer> numbers) {
+                if (numbers.size() != 6) {
+                    throw new IllegalArgumentException(SIXNUMBER.getMessage());
+        }
+    }
+    public void checkSame(Integer bonusNumber, List<List<Integer>> lottoNumber) {
+        bonusDuplication(bonusNumber);
+        for (List<Integer> integers : lottoNumber) {
+            List<Integer> Result = integers.stream()
+                    .filter(i -> this.numbers.stream().anyMatch(Predicate.isEqual(i)))
+                    .toList();
+            long bonusResult = integers.stream()
+                    .filter(bonusNumber::equals).count();
+            CheckPrize(Result.size(), bonusResult).addWinCount();
+
+        }
+    }
+
+    private void bonusDuplication(Integer bonusNumber) {
+        List<Integer> Result = this.numbers.stream()
+                .filter(i-> !Objects.equals(i, bonusNumber))
+                .toList();
+        if(Result.size()!=6){
+            throw new IllegalArgumentException(DUPLICATION.getMessage());
+        }
+
+    }
+
+    public LottoPrize CheckPrize(int result, long bonusResult){
+        if(result==6){
+            return FIRST_PRIZE;
+        }
+        if(result==5&&bonusResult==1){
+            return SECOND_PRIZE;
+        }
+        if(result==5&&bonusResult==0){
+            return THIRD_PRIZE;
+        }
+        if(result==4){
+            return FOURTH_PRIZE;
+        }
+        if(result==3){
+            return FIFTH_PRIZE;
+        }
+        if(result<3){
+            return LOOSE;
+        }
+        throw new IllegalArgumentException("존재 하지 않는 순위입니다.");
+    }
+}

리뷰: 매직넘버 처리를 해주셔야 할것 같아요!
@@ -0,0 +1,67 @@
+package lotto.model;
+
+import camp.nextstep.edu.missionutils.Randoms;
+import lotto.controller.LottoController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static lotto.constants.ErrorMessage.ISNOTINTEGER;
+import static lotto.constants.ErrorMessage.NOTTHOUSAND;
+
+public class LottoNumberMaker {
+    private static int buyPrice;
+    private static final List<List<Integer>> numbers = new ArrayList<>();
+    private static final LottoController lottoController = new LottoController();
+
+    public static int getBuyPrice() {
+        return buyPrice;
+    }
+
+    public void makeLottoNumber(Integer count) {
+        buyPrice = count;
+        checkThousand(count);
+        IntStream.range(0, count / 1000)
+                .forEach(i -> numbers.add(makeRandomNumber()));
+    }
+
+    private void checkThousand(Integer count) {
+        if(count%1000!=0){
+           throw new IllegalArgumentException(NOTTHOUSAND.getMessage());
+        }
+        return;
+    }
+
+    private List<Integer> makeRandomNumber() {
+        return Randoms.pickUniqueNumbersInRange(1, 45, 6).stream()
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    public void checkInt() {
+        while (true) {
+            try {
+                int number = checkCount();
+                makeLottoNumber(number);
+                break;
+            } catch (IllegalArgumentException e) {
+                System.out.println(ISNOTINTEGER.getMessage());
+                System.out.println(NOTTHOUSAND.getMessage());
+            }
+        }
+    }
+
+    private int checkCount() {
+        try {
+            return Integer.parseInt(lottoController.askPrice());
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(ISNOTINTEGER.getMessage());
+        }
+    }
+
+    public List<List<Integer>> getLottoNumber() {
+        return numbers;
+    }
+}

리뷰: 이부분만 따로 전역 메서드로 선언하신 이유가 있으실까요???
@@ -0,0 +1,67 @@
+package lotto.model;
+
+import camp.nextstep.edu.missionutils.Randoms;
+import lotto.controller.LottoController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static lotto.constants.ErrorMessage.ISNOTINTEGER;
+import static lotto.constants.ErrorMessage.NOTTHOUSAND;
+
+public class LottoNumberMaker {
+    private static int buyPrice;
+    private static final List<List<Integer>> numbers = new ArrayList<>();
+    private static final LottoController lottoController = new LottoController();
+
+    public static int getBuyPrice() {
+        return buyPrice;
+    }
+
+    public void makeLottoNumber(Integer count) {
+        buyPrice = count;
+        checkThousand(count);
+        IntStream.range(0, count / 1000)
+                .forEach(i -> numbers.add(makeRandomNumber()));
+    }
+
+    private void checkThousand(Integer count) {
+        if(count%1000!=0){
+           throw new IllegalArgumentException(NOTTHOUSAND.getMessage());
+        }
+        return;
+    }
+
+    private List<Integer> makeRandomNumber() {
+        return Randoms.pickUniqueNumbersInRange(1, 45, 6).stream()
+                .sorted()
+                .collect(Collectors.toList());
+    }
+
+    public void checkInt() {
+        while (true) {
+            try {
+                int number = checkCount();
+                makeLottoNumber(number);
+                break;
+            } catch (IllegalArgumentException e) {
+                System.out.println(ISNOTINTEGER.getMessage());
+                System.out.println(NOTTHOUSAND.getMessage());
+            }
+        }
+    }
+
+    private int checkCount() {
+        try {
+            return Integer.parseInt(lottoController.askPrice());
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(ISNOTINTEGER.getMessage());
+        }
+    }
+
+    public List<List<Integer>> getLottoNumber() {
+        return numbers;
+    }
+}

리뷰: 해당 클래스가 너무 많은 책임을 가지고 있는것 같습니다. 구매금액을 검증하는 부분과 로또 번호를 검증하는 부분을 분리하는 것도 좋은 방법일거 같습니다.
@@ -0,0 +1,39 @@
+package lotto.model.constants;
+
+public enum LottoPrize {
+    FIRST_PRIZE(0,"6개 일치 (2,000,000,000원) - ","개",2000000000),
+    SECOND_PRIZE(0,"5개 일치, 보너스 볼 일치 (30,000,000원) - ","개", 30000000),
+    THIRD_PRIZE(0,"5개 일치 (1,500,000원) - ","개", 1500000),
+    FOURTH_PRIZE(0,"4개 일치 (50,000원) - ","개", 50000),
+    FIFTH_PRIZE(0,"3개 일치 (5,000원) - ","개", 5000),
+    LOOSE(0,"","개", 0);
+
+
+    private int winCount;
+    private final String text;
+    private final String unit;
+    private  int prizeMoney;
+
+    LottoPrize(int winCount, String text, String unit, int prizemoney) {
+        this.winCount = winCount;
+        this.text = text;
+        this.unit = unit;
+        this.prizeMoney = prizemoney;
+    }
+    public int getWinCount() {
+        return winCount;
+    }
+    public String getText() {
+        return text;
+    }
+    public String getUnit() {
+        return unit;
+    }
+    public int getPrizeMoney() {
+        return prizeMoney;
+    }
+
+    public void addWinCount() {
+        this.winCount ++;
+    }
+}

리뷰: 출력 형식과 관련된 부분은 view에서 처리해야할거 같은데 이에 대해서 어떻게 생각하시나요?
@@ -0,0 +1,100 @@
+# Domain 구현
+
+## 진행 프로세스 (시스템 책임)
+
+1. 게이머는 상대할 보스 몬스터의 HP를 설정한다.
+2. 게이머는 플레이할 플레이어의 이름과 HP, MP를 설정한다.
+3. 게임이 시작된다.
+4. 게임은 턴제이며, 매 턴마다 다음과 같은 행동이 반복된다.
+   1) 보스 몬스터와 플레이어의 현재 상태를 보여준다.
+   2) 플레이어가 공격할 방식을 선택한다.
+   3) 플레이어가 선택된 방식으로 공격한다. (보스 몬스터에게 데미지를 입힘)
+   4) 데미지를 입은 보스 몬스터의 상태를 확인한다.
+   5) 보스 몬스터가 죽었다면 게임이 종료된다.
+   6) 보스 몬스터가 살아있다면 플레이어를 공격한다.
+   7) 데미지를 입은 플레이어의 상태를 확인한다.
+   8) 플레이어가 죽었다면 게임이 종료된다.
+5. 게임 종료 후 승자를 안내한다.
+   - 플레이어가 이겼을 경우 : 진행한 턴 수를 알려준다.
+   - 보스 몬스터가 이겼을 경우 : 플레이어와 보스 몬스터의 현재 상태를 보여준다.
+
+## Domain 객체 선정 및 책임과 협력 할당
+
+1. **Raid Game**
+   - 게임 시작 전 주요 인물에 대해 셋팅할 책임을 가짐
+     - 게임 인물인 **Boss Monster**를 생성할 책임을 가짐
+     - 게임 인물인 **Player**를 생성할 책임을 가짐
+   - 매 턴을 실행할 책임을 가짐
+       - 게임 상태를 확인할 책임을 가짐 (게임 상태가 '종료'일 경우 턴을 실행하지 않음)
+       - 턴 수를 증가시킬 책임을 가짐
+       - **Player**가 **Boss Monster**를 선택된 공격 방식으로 공격하도록 할 책임을 가짐
+         - **Player**의 공격 행동에 대한 결과를 제공받고, **Boss Monster**에게 전달할 책임을 가짐 (**Player**의 공격과 **Boss Monster**의 피해 행동에 대한 협력 필요)
+         - **Boss Monster**의 생존여부에 따라 게임 상태를 변경할 책임을 가짐 (**Boss Monster**의 상태를 제공받는 협력 필요)
+       - **Boss Monster**가 **Player**를 공격하도록 할 책임을 가짐 (**Boss Monster**의 공격과 **Player**의 피해 행동에 대한 협력 필요)
+           - **Boss Monster**의 공격 행동에 대한 결과를 제공받고, **Player**에게 전달할 책임을 가짐 (**Boss Monster**의 공격과 **Player**의 피해 행동에 대한 협력 필요)
+           - **Player**의 생존여부에 따라 게임 상태를 변경할 책임을 가짐 (**Player**의 상태를 제공받는 협력 필요)
+       - 해당 턴에 대한 게임 기록을 생성할 책임을 가짐 (**GameHistory**에게 턴에 대한 기록을 생성하는 협력 필요)
+
+2. **Boss Monster**
+   - 현재 상태를 제공해줄 책임을 가짐 (총 HP, 현재 HP)
+   - 공격 명령을 수행할 책임을 가짐 (0~20의 랜덤 데미지)
+   - 공격 피해 입음을 수행할 책임을 가짐 (현재 HP 감소)
+
+3. **Player**
+   - 현재 상태를 제공해줄 책임을 가짐 (이름, 총 HP, 현재 HP, 총 MP, 현재 MP)
+   - 공격 명령을 수행할 책임을 가짐 (**Attack Type**에 대한 정보를 제공받는 협력 필요, MP 감소)
+   - 공격 피해 입음을 수행할 책임을 가짐 (현재 HP 감소)
+
+4. **Attack Type**
+    - 공격 방식 종류를 제공해줄 책임을 가짐 (공격 변호, 공격 방식 이름)
+    - 공격 방식 수행에 대한 정보를 제공해줄 책임을 가짐 (데미지, MP 소모량, MP 회복량)
+
+5. **Game History**
+   - 매 턴에 대한 기록을 저장할 책임을 가짐
+   - 추후 Controller의 Veiw를 위한 요청에 응답 가능
+
+## 주요 메시지 구성 (공용 인터페이스)
+
+1. 보스 몬스터 설정을 요청
+   - 수신자 : Raid Game
+   - 이름 : Create Boss Monster
+   - 인자 : int hp
+   - 응답 : void, Boss Monster 객체 생성
+
+2. 플레이어 설정을 요청
+    - 수신자 : Raid Game
+    - 이름 : Create Player
+    - 인자 : String name, int hp, int mp
+    - 응답 : void, Player 객체 생성
+
+3. 턴 진행을 요청
+   - 수신자 : Raid Game
+   - 이름 : Start Game
+   - 인자 : -
+   - 응답 : 구성된 턴 로직 실행
+
+4. 게임 상태 확인을 요청
+    - 수신자 : Raid Game
+    - 이름 : Check Game Status
+    - 인자 : -
+    - 응답 : return Game Status (true or False)
+
+5. 턴 횟수 증가를 요청
+    - 수신자 : Raid Game
+    - 이름 : Increase Turns
+    - 인자 : -
+    - 응답 : void, Turn 1 증가
+
+6. 공격 행동 수행을 요청
+   - 수신자 : Player, Boss Monster
+   - 이름 : Attack
+   - 인자 : -
+   - 응답 : return 데미지, 공격 방식에 따라 MP 감소(Player)
+
+7. 공격 피해 전달을 요청
+    - 수신자 : Player, Boss Monster
+    - 이름 : take Damage
+    - 인자 : int damage
+    - 응답 : return 현재 HP
+
+

리뷰: 요청 사항을 굉장히 깔끔하게 적어주신 것 같아요!
하지만 우려되는 점도 있는데요. 정성스레 작성해주신 문서지만 동료 입장에서는 함수 이름이나 인자 등을 글로 표현하는 것보다 함수 형태를 보여주는 것이 가독성이 더 좋을 수도 있겠다는 생각을 했어요!
책들도 보면 글보다는 코드로 먼저 보여주잖아요:)
```java
public void start() {
    // 게임 시작 로직
}
```
이런 느낌으로요!

어떻게 생각하시나요?
@@ -0,0 +1,17 @@
+package bossmonster.exception;
+
+import bossmonster.view.OutputView;
+import java.util.function.Supplier;
+
+public class ExceptionHandler {
+
+    public static <T> T retryInput(Supplier<T> supplier) {
+        while (true) {
+            try {
+                return supplier.get();
+            } catch (Exception exception) {
+                OutputView.printError(exception);
+            }
+        }
+    }
+}

리뷰: 이렇게 만들 생각을 하진 못했는데, 제네릭을 정말 잘 활용하신 것 같아요!
하지만 함수명에서 오해의 소지가 있다고 생각해요. 첫 시도를 할 때도 해당 함수를 사용하기 때문인데요. 오류가 나지 않을때까지 계속 재입력 받는 것이기 때문에 다른 네이밍이 어울릴 것 같아요! 음... 마땅히 떠오르는 네이밍은 없네요ㅠㅠ
@@ -0,0 +1,17 @@
+package bossmonster.exception;
+
+import bossmonster.view.OutputView;
+import java.util.function.Supplier;
+
+public class ExceptionHandler {
+
+    public static <T> T retryInput(Supplier<T> supplier) {
+        while (true) {
+            try {
+                return supplier.get();
+            } catch (Exception exception) {
+                OutputView.printError(exception);
+            }
+        }
+    }
+}

리뷰: 추가적으로 클래스명이 어울리지 않는듯한 느낌을 받았어요. 스프링을 생각해서 네이밍을 정하신 것 같아서 스프링의 ExceptionHandler와 비교해서 말씀드리겠습니다!

`ExceptionHandler`의 경우 말 그대로 예외를 핸들링해주는 역할입니다. A라는 예외가 발생하면 ExceptionHandler가 그에 맞게 처리해주고, B라는 예외가 발생하면 그것도 그것의 ExceptionHandler에 맞게 처리해주는 역할이죠. 스프링의 ExceptionHandler처럼 예외를 핸들링하는 그 자체에만 목적이 있어야한다고 생각해요.

하지만 작성하신 코드에서는 예외가 발생했을 때 이벤트가 예외를 감지해 예외를 핸들링하는 것이 아니라, 마치 예외가 발생할법한 함수들을 대신 실행해주는 역할같아요. 넵, 그저 함수형 인터페이스죠. 그렇다면 이것에 맞는 네이밍으로 하는 것이 좋지 않을까요?

만약 `ExceptionHandler`를 사용하고 싶으면 아래와 같이 되어야할 것 같습니다.
```java
public static T handle(Exception e) {
    // 핸들링
}
```
@@ -0,0 +1,78 @@
+package bossmonster.exception;
+
+import bossmonster.view.constants.Message;
+
+public class Validator {
+
+    public static String validateInputOfNumber(String inputValue) {
+        validateEmpty(inputValue);
+        validateInteger(inputValue);
+        return inputValue;
+    }
+
+    public static String validatePlayerName(String inputValue) {
+        validateEmpty(inputValue);
+        validateRangeOfPlayerName(inputValue);
+        return inputValue;
+    }
+
+    public static String[] validateInputOfNumbers(String inputValue) {
+        validateSeparated(inputValue);
+        String[] separatedValue = inputValue.split(",");
+        validateArray(separatedValue);
+        for (String value : separatedValue) {
+            validateEmpty(value);
+            validateInteger(value);
+        }
+        return separatedValue;
+    }
+
+    public static int validateBossMonster(int hp) {
+        return validateRangeOfMonster(hp);
+    }
+
+    public static void validatePlayerStatus(int hp, int mp) {
+        if (hp + mp != 200) {
+            throw new IllegalArgumentException(Message.ERROR_PLAYER_STATUS.getErrorMessage());
+        }
+    }
+
+    private static void validateEmpty(String inputValue) {
+        if (inputValue.isEmpty()) {
+            throw new IllegalArgumentException(Message.ERROR_EMPTY.getErrorMessage());
+        }
+    }
+
+    private static void validateInteger(String inputValue) {
+        try {
+            Integer.parseInt(inputValue);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(Message.ERROR_NOT_INTEGER.getErrorMessage());
+        }
+    }
+
+    private static void validateSeparated(String inputValue) {
+        if (!inputValue.contains(",")) {
+            throw new IllegalArgumentException(Message.ERROR_NOT_COMMA.getErrorMessage());
+        }
+    }
+
+    private static void validateArray(String[] inputValue) {
+        if (inputValue.length != 2) {
+            throw new IllegalArgumentException(Message.ERROR_ARRAY_SIZE.getErrorMessage());
+        }
+    }
+
+    private static int validateRangeOfMonster(int hp) {
+        if (hp < 100 || hp > 300) {
+            throw new IllegalArgumentException(Message.ERROR_BOSS_MONSTER_HP.getErrorMessage());
+        }
+        return hp;
+    }
+
+    private static void validateRangeOfPlayerName(String name) {
+        if (name.length() > 5) {
+            throw new IllegalArgumentException(Message.ERROR_PLAYER_NAME.getErrorMessage());
+        }
+    }
+}

리뷰: 해당 클래스를 exception 패키지에 넣으신 이유가 궁금합니다!

hp + mp는 200이어야한다 등... 비즈니스 로직이 담긴 부분이 있는데 domain 패키지와 분리되어 있어서요!
@@ -0,0 +1,61 @@
+package bossmonster.domain;
+
+import bossmonster.exception.Validator;
+
+public class Player {
+
+    private String name;
+    private PlayerStatus status;
+
+    public Player(String name, int maxHP, int maxMP) {
+        this.name = Validator.validatePlayerName(name);
+        Validator.validatePlayerStatus(maxHP, maxMP);
+        this.status = new PlayerStatus(maxHP, maxMP);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isAlive() {
+        return status.isAlive();
+    }
+
+    public int getMaxHP() {
+        return status.getMaxHP();
+    }
+
+    public int getCurrentHP() {
+        return status.getCurrentHP();
+    }
+
+    public int getMaxMP() {
+        return status.getMaxMP();
+    }
+
+    public int getCurrentMP() {
+        return status.getCurrentMP();
+    }
+
+    public int attack(AttackType attackType) {
+        if (attackType.getName().equals(AttackType.ATTACK_TYPE_NORMAL.getName())) {
+            recoverMP(attackType.getMpRecover());
+        }
+        if (attackType.getName().equals(AttackType.ATTACK_TYPE_MAGIC.getName())) {
+            consumeMP(attackType.getMpUsage());
+        }
+        return attackType.getDamage();
+    }
+
+    public void takeDamage(int damage) {
+        status.setCurrentHP(status.getCurrentHP() - damage);
+    }
+
+    private void recoverMP(int mp) {
+        status.setCurrentMP(status.getCurrentMP() + mp);
+    }
+
+    private void consumeMP(int mp) {
+        status.setCurrentMP(status.getCurrentMP() - mp);
+    }
+}

리뷰: controller에서 Validator를 사용할 때도 있고, domain에서 사용할 때도 있군요.
어떤 기준으로 분리하셨는지 궁금합니다!
@@ -0,0 +1,70 @@
+package bossmonster.domain;
+
+import bossmonster.domain.dto.GameHistoryDto;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GameHistory {
+
+    private class Turns {
+
+        private int turnCount;
+        private String playerName;
+        private String playerAttackType;
+        private int playerAttackDamage;
+        private int monsterAttackDamage;
+        private int playerMaxHP;
+        private int playerCurrentHP;
+        private int playerMaxMP;
+        private int playerCurrentMP;
+        private int monsterMaxHP;
+        private int monsterCurrentHP;
+        private boolean gameStatus;
+
+        public Turns(int turnCount, String playerAttackType, int playerAttackDamage,
+                     int monsterAttackDamage, boolean gameStatus, Player player, BossMonster bossMonster) {
+            this.turnCount = turnCount;
+            this.playerName = player.getName();
+            this.playerAttackType = playerAttackType;
+            this.playerAttackDamage = playerAttackDamage;
+            this.monsterAttackDamage = monsterAttackDamage;
+            this.playerMaxHP = player.getMaxHP();
+            this.playerCurrentHP = player.getCurrentHP();
+            this.playerMaxMP = player.getMaxMP();
+            this.playerCurrentMP = player.getCurrentMP();
+            this.monsterMaxHP = bossMonster.getMaxHP();
+            this.monsterCurrentHP = bossMonster.getCurrentHP();
+            this.gameStatus = gameStatus;
+        }
+    }
+
+    private static final String DEFAULT_ATTACK_TYPE = "";
+    private static final int DEFAULT_DAMAGE = 0;
+    private int recentRecord;
+    private List<Turns> raidHistory = new ArrayList<>();
+
+    public void addHistory(int turnCount, boolean gameStatus, Player player, BossMonster bossMonster) {
+        raidHistory.add(
+                new Turns(turnCount, DEFAULT_ATTACK_TYPE, DEFAULT_DAMAGE, DEFAULT_DAMAGE, gameStatus, player,
+                        bossMonster));
+    }
+
+    public void addHistory(int turnCount, String playerAttackType, int playerAttackDamage,
+                           int monsterAttackDamage, boolean gameStatus, Player player, BossMonster bossMonster) {
+        raidHistory.add(
+                new Turns(turnCount, playerAttackType, playerAttackDamage, monsterAttackDamage, gameStatus, player,
+                        bossMonster));
+    }
+
+    public GameHistoryDto requestRaidHistory() {
+        setRecentRecord();
+        Turns turns = raidHistory.get(recentRecord);
+        return new GameHistoryDto(turns.turnCount, turns.playerName, turns.playerAttackType, turns.playerAttackDamage,
+                turns.monsterAttackDamage, turns.playerMaxHP, turns.playerCurrentHP, turns.playerMaxMP,
+                turns.playerCurrentMP, turns.monsterMaxHP, turns.monsterCurrentHP, turns.gameStatus);
+    }
+
+    private void setRecentRecord() {
+        recentRecord = raidHistory.size() - 1;
+    }
+}

리뷰: 해당 객체를 만드신 목적이 궁금합니다!