ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,50 @@
+package step1;
+
+import java.util.List;
+
+public class Calculator {
+
+    private CalculatorResource calculatorResource;
+
+    public Calculator(String stringCalculatorSentence) {
+        this.calculatorResource = new CalculatorResource(stringCalculatorSentence);
+    }
+
+    public int calculate() {
+
+        List<Integer> numberList = calculatorResource.getNumberArray();
+        List<String> operatorList = calculatorResource.getOperatorArray();
+
+        int operatorListIndex = 0;
+        int result = 0;
+
+        for (int i = 1; i < numberList.size(); i++) {
+
+            result = calcualteInit(numberList, result, i);
+
+            result = getResult(numberList, operatorList, operatorListIndex, result, i);
+            operatorListIndex++;
+        }
+        return result;
+    }
+
+    private int calcualteInit(List<Integer> numberList, int result, int i) {
+        if (i == 1) {
+            result = (numberList.get(i - 1));
+        }
+        return result;
+    }
+
+    private int getResult(List<Integer> numberList, List<String> operatorList, int operatorListIndex, int result, int i) {
+        if (operatorList.get(operatorListIndex).equals("+")) {
+            result = result + (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("-")) {
+            result = result - (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("*")) {
+            result = result * (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("/")) {
+            result = result / (numberList.get(i));
+        }
+        return result;
+    }
+}

리뷰: java의 Enum 클래스를 사용하면 상태와 행위를 한곳에서 관리할 수 있는데요! 

링크를 보시고 참고하셔서 enum 클래스를 사용해보면 좋을 것 같습니다 :)

https://techblog.woowahan.com/2527/
@@ -0,0 +1,50 @@
+package step1;
+
+import java.util.List;
+
+public class Calculator {
+
+    private CalculatorResource calculatorResource;
+
+    public Calculator(String stringCalculatorSentence) {
+        this.calculatorResource = new CalculatorResource(stringCalculatorSentence);
+    }
+
+    public int calculate() {
+
+        List<Integer> numberList = calculatorResource.getNumberArray();
+        List<String> operatorList = calculatorResource.getOperatorArray();
+
+        int operatorListIndex = 0;
+        int result = 0;
+
+        for (int i = 1; i < numberList.size(); i++) {
+
+            result = calcualteInit(numberList, result, i);
+
+            result = getResult(numberList, operatorList, operatorListIndex, result, i);
+            operatorListIndex++;
+        }
+        return result;
+    }
+
+    private int calcualteInit(List<Integer> numberList, int result, int i) {
+        if (i == 1) {
+            result = (numberList.get(i - 1));
+        }
+        return result;
+    }
+
+    private int getResult(List<Integer> numberList, List<String> operatorList, int operatorListIndex, int result, int i) {
+        if (operatorList.get(operatorListIndex).equals("+")) {
+            result = result + (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("-")) {
+            result = result - (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("*")) {
+            result = result * (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("/")) {
+            result = result / (numberList.get(i));
+        }
+        return result;
+    }
+}

리뷰: 메서드의 파라미터의 개수를 2개 이하로 리팩터링해보는건 어떨까요?
클린 코드 책에서는 메서드의 파라미터 개수는 0~2개가 적절하며 4개 이상은 무조건적으로 피해야한다고 이야기합니다.
파라미터의 개수가 많을 수록 하나의 메서드에서 하는 일이 많아질 수 있고 코드를 읽기 어려워지기 때문입니다 :)
@@ -0,0 +1,50 @@
+package step1;
+
+import java.util.List;
+
+public class Calculator {
+
+    private CalculatorResource calculatorResource;
+
+    public Calculator(String stringCalculatorSentence) {
+        this.calculatorResource = new CalculatorResource(stringCalculatorSentence);
+    }
+
+    public int calculate() {
+
+        List<Integer> numberList = calculatorResource.getNumberArray();
+        List<String> operatorList = calculatorResource.getOperatorArray();
+
+        int operatorListIndex = 0;
+        int result = 0;
+
+        for (int i = 1; i < numberList.size(); i++) {
+
+            result = calcualteInit(numberList, result, i);
+
+            result = getResult(numberList, operatorList, operatorListIndex, result, i);
+            operatorListIndex++;
+        }
+        return result;
+    }
+
+    private int calcualteInit(List<Integer> numberList, int result, int i) {
+        if (i == 1) {
+            result = (numberList.get(i - 1));
+        }
+        return result;
+    }
+
+    private int getResult(List<Integer> numberList, List<String> operatorList, int operatorListIndex, int result, int i) {
+        if (operatorList.get(operatorListIndex).equals("+")) {
+            result = result + (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("-")) {
+            result = result - (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("*")) {
+            result = result * (numberList.get(i));
+        } else if (operatorList.get(operatorListIndex).equals("/")) {
+            result = result / (numberList.get(i));
+        }
+        return result;
+    }
+}

리뷰: `계산기`가 하나의 `계산기 자원`을 상태로 가지도록 구현하셨네요 !
만약 계산기가 또 다른 자원에 대한 계산을 해야하는 상황이라면 어떻게 해야할까요?

현재 상태에서는 하나의 계산기 객체가 하나의 자원만을 계산할 수 있는데요. 
여러 개의 자원에 대해 계산할 수 있도록 개선해보면 좋을 것 같습니다 :)
@@ -0,0 +1,64 @@
+package step1;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CalculatorResource {
+
+    private String sentence;
+    private String[] sentenceArray;
+    private List<Integer> numberArray;
+    private List<String> operatorArray;
+
+    public List<Integer> getNumberArray() {
+        return numberArray;
+    }
+
+    public List<String> getOperatorArray() {
+        return operatorArray;
+    }
+
+    public CalculatorResource(String sentence) {
+        this.sentence = sentence;
+        splitSentence();
+        creatNumberList();
+        creatOperatorList();
+    }
+
+    private void splitSentence() {
+        this.sentenceArray = this.sentence.split(" ");
+    }
+
+    public void creatNumberList() {
+        this.numberArray = new ArrayList<>();
+
+        for (String s : sentenceArray) {
+            char numberCheck = s.charAt(0);
+            validateNumber(numberArray, s, numberCheck);
+        }
+        this.numberArray = numberArray;
+    }
+
+    private void validateNumber(List<Integer> numberArray, String s, char numberCheck) {
+        if (numberCheck > 48 && numberCheck < 58) {
+            this.numberArray.add(Integer.parseInt(s));
+        }
+    }
+
+    public void creatOperatorList() {
+        this.operatorArray = new ArrayList<>();
+
+        for (String s : sentenceArray) {
+            char operatorCheck = s.charAt(0);
+            validateOperator(operatorArray, s, operatorCheck);
+        }
+    }
+
+    private void validateOperator(List<String> operatorArray, String s, char operatorCheck) {
+        if (operatorCheck < 48 || operatorCheck > 58) {
+            this.operatorArray.add(s);
+        }
+    }
+
+
+}

리뷰: CalculatorResource 클래스 네이밍은 추상화가 많이 되어 있는 클래스 명입니다.
클래스 내부를 보지 않으면 어떤 상태를 가지고 있는지 유추하기 힘듭니다. 조금 더 구체적인 클래스 명을 만들어보면 좋을 것 같아요 :)
@@ -0,0 +1,64 @@
+package step1;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CalculatorResource {
+
+    private String sentence;
+    private String[] sentenceArray;
+    private List<Integer> numberArray;
+    private List<String> operatorArray;
+
+    public List<Integer> getNumberArray() {
+        return numberArray;
+    }
+
+    public List<String> getOperatorArray() {
+        return operatorArray;
+    }
+
+    public CalculatorResource(String sentence) {
+        this.sentence = sentence;
+        splitSentence();
+        creatNumberList();
+        creatOperatorList();
+    }
+
+    private void splitSentence() {
+        this.sentenceArray = this.sentence.split(" ");
+    }
+
+    public void creatNumberList() {
+        this.numberArray = new ArrayList<>();
+
+        for (String s : sentenceArray) {
+            char numberCheck = s.charAt(0);
+            validateNumber(numberArray, s, numberCheck);
+        }
+        this.numberArray = numberArray;
+    }
+
+    private void validateNumber(List<Integer> numberArray, String s, char numberCheck) {
+        if (numberCheck > 48 && numberCheck < 58) {
+            this.numberArray.add(Integer.parseInt(s));
+        }
+    }
+
+    public void creatOperatorList() {
+        this.operatorArray = new ArrayList<>();
+
+        for (String s : sentenceArray) {
+            char operatorCheck = s.charAt(0);
+            validateOperator(operatorArray, s, operatorCheck);
+        }
+    }
+
+    private void validateOperator(List<String> operatorArray, String s, char operatorCheck) {
+        if (operatorCheck < 48 || operatorCheck > 58) {
+            this.operatorArray.add(s);
+        }
+    }
+
+
+}

리뷰: 객체가 생성된 이후에 두 변수는 사용되지 않고 있네요! 🤔 

그렇다면 계산기 자원클래스에서 sentence와 sentenceArray를 상태로 가지고 있을 필요가 있을까요?
@@ -0,0 +1,36 @@
+import EventCalendar from '../../src/domain/EventCalendar';
+import { CHRISTMAS_D_DAY, GIFT, SPECIAL } from '../../src/domain/Events';
+
+import {
+  EVENT_MONTH,
+  EVENT_NAMES,
+  EVENT_YEAR,
+} from '../../src/constants/event';
+import { MAIN_COURSES } from '../../src/constants/menus';
+
+describe('EventCalendar 테스트', () => {
+  test('getEventBenefit 기능 테스트', () => {
+    // given
+    const YEAR = EVENT_YEAR;
+    const MONTH = EVENT_MONTH;
+    const DATE = 25;
+    const TOTAL_PRICE = 130_000;
+    const ORDER_CATEGORIES = [MAIN_COURSES];
+
+    const RESULT = {
+      [EVENT_NAMES.CHRISTMAS_D_DAY]: CHRISTMAS_D_DAY.getEvent().getBenefit,
+      [EVENT_NAMES.SPECIAL]: SPECIAL.getEvent().getBenefit,
+      [EVENT_NAMES.GIFT]: GIFT.getEvent().getBenefit,
+    };
+
+    // when
+    const eventCalendar = new EventCalendar(YEAR, MONTH, DATE);
+    eventCalendar.setAvailableEvents({
+      totalPrice: TOTAL_PRICE,
+      orderCategories: ORDER_CATEGORIES,
+    });
+
+    //then
+    expect(eventCalendar.availableEvents).toEqual(RESULT);
+  });
+});

리뷰: 테스트 코드에서 실제 코드에서 사용되는 상수를 사용하는 것은 좋지 않아 보입니다.
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../../src/constants/event';
+import EventPlanner from '../../src/services/EventPlanner';
+
+const ORDERS = [
+  { menu: '양송이수프', amount: 1 },
+  { menu: '타파스', amount: 1 },
+  { menu: '티본스테이크', amount: 2 },
+  { menu: '초코케이크', amount: 1 },
+  { menu: '아이스크림', amount: 1 },
+];
+
+async function getEventPlanner(orders) {
+  // given
+  const VISIT_DATE = 25;
+
+  // when
+  const eventPlanner = new EventPlanner(VISIT_DATE);
+  await eventPlanner.generateReceipt(orders);
+  await eventPlanner.generateBenefits();
+
+  return eventPlanner;
+}
+
+describe('EventPlanner 기능 테스트', () => {
+  test.each([32, 3.1])('validate - 정상 작동', async (input) => {
+    expect(() => new EventPlanner(input)).toThrow('[ERROR]');
+  });
+});
+
+describe('EventPlanner 혜택 조회 테스트', () => {
+  test('접근자 프로퍼티 테스트 - gift', async () => {
+    const gift = {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+
+    const eventPlanner = await getEventPlanner(ORDERS);
+
+    expect(eventPlanner.gift).toEqual(gift);
+  });
+
+  test('접근자 프로퍼티 테스트 - benefits', async () => {
+    const benefits = {
+      [EVENT_NAMES.CHRISTMAS_D_DAY]: { amount: 1, price: 3400 },
+      [EVENT_NAMES.SPECIAL]: { amount: 1, price: 1000 },
+      [EVENT_NAMES.WEEKDAY]: { amount: 2, price: 2023 },
+      [EVENT_NAMES.GIFT]: {
+        menu: '샴페인',
+        amount: 1,
+        price: 25_000,
+      },
+    };
+
+    const eventPlanner = await getEventPlanner(ORDERS);
+
+    expect(eventPlanner.benefits).toEqual(benefits);
+  });
+
+  test('접근자 프로퍼티 테스트 - totalBenefitMoney', async () => {
+    const totalBenefitMoney = 33_446;
+
+    const eventPlanner = await getEventPlanner(ORDERS);
+
+    expect(eventPlanner.totalBenefitMoney).toBe(totalBenefitMoney);
+  });
+
+  test('접근자 프로퍼티 테스트 - payment', async () => {
+    const originalPrice = 141_500;
+    const discountAmount = 8_446;
+
+    const eventPlanner = await getEventPlanner(ORDERS);
+
+    expect(eventPlanner.payment).toBe(originalPrice - discountAmount);
+  });
+
+  test.each([
+    {
+      orders: [
+        { menu: '양송이수프', amount: 1 },
+        { menu: '타파스', amount: 1 },
+        { menu: '티본스테이크', amount: 2 },
+        { menu: '초코케이크', amount: 1 },
+        { menu: '아이스크림', amount: 1 },
+      ],
+      badge: '산타',
+    },
+    {
+      orders: [
+        { menu: '양송이수프', amount: 1 },
+        { menu: '타파스', amount: 1 },
+        { menu: '티본스테이크', amount: 1 },
+        { menu: '아이스크림', amount: 4 },
+      ],
+      badge: '트리',
+    },
+    {
+      orders: [
+        { menu: '양송이수프', amount: 1 },
+        { menu: '타파스', amount: 1 },
+        { menu: '아이스크림', amount: 1 },
+      ],
+      badge: '별',
+    },
+    {
+      orders: [
+        { menu: '양송이수프', amount: 1 },
+        { menu: '타파스', amount: 1 },
+      ],
+      badge: '없음',
+    },
+  ])('접근자 프로퍼티 테스트 - badge', async ({ orders, badge }) => {
+    const eventPlanner = await getEventPlanner(orders);
+
+    expect(eventPlanner.badge).toBe(badge);
+  });
+});

리뷰: "\_"새롭게 배워갑니다!
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../constants/event.js';
+import { DESSERTS, MAIN_COURSES } from '../constants/menus.js';
+
+export const CHRISTMAS_D_DAY = {
+  getBenefit({ date }) {
+    const baseAmount = 1000;
+    const weightAmount = 100;
+
+    return {
+      amount: 1,
+      price: baseAmount + weightAmount * (date - 1),
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.CHRISTMAS_D_DAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isChristmasPeriod }) {
+    return isChristmasPeriod === true;
+  },
+};
+
+export const WEEKDAY = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[DESSERTS],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKDAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === false && orderCategories.includes(DESSERTS);
+  },
+};
+
+export const WEEKEND = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[MAIN_COURSES],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKEND,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === true && orderCategories.includes(MAIN_COURSES);
+  },
+};
+
+export const SPECIAL = {
+  getBenefit() {
+    const discountAmount = 1_000;
+    return {
+      amount: 1,
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.SPECIAL,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isSpecialDate }) {
+    return isSpecialDate === true;
+  },
+};
+
+export const GIFT = {
+  getBenefit() {
+    return {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.GIFT,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ totalPrice }) {
+    return totalPrice >= 120_000;
+  },
+};
+
+export const ALL_EVENTS = Object.freeze({
+  CHRISTMAS_D_DAY,
+  WEEKDAY,
+  WEEKEND,
+  SPECIAL,
+  GIFT,
+});

리뷰: isWeekend === true는 불필요해 보이는데, 사용하신 이유가 있으신가요?
@@ -0,0 +1,117 @@
+import { EVENT_NAMES } from '../constants/event.js';
+import { DESSERTS, MAIN_COURSES } from '../constants/menus.js';
+
+export const CHRISTMAS_D_DAY = {
+  getBenefit({ date }) {
+    const baseAmount = 1000;
+    const weightAmount = 100;
+
+    return {
+      amount: 1,
+      price: baseAmount + weightAmount * (date - 1),
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.CHRISTMAS_D_DAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isChristmasPeriod }) {
+    return isChristmasPeriod === true;
+  },
+};
+
+export const WEEKDAY = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[DESSERTS],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKDAY,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === false && orderCategories.includes(DESSERTS);
+  },
+};
+
+export const WEEKEND = {
+  getBenefit({ orderCntByCategory }) {
+    const discountAmount = 2_023;
+    return {
+      amount: orderCntByCategory[MAIN_COURSES],
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.WEEKEND,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isWeekend, orderCategories }) {
+    return isWeekend === true && orderCategories.includes(MAIN_COURSES);
+  },
+};
+
+export const SPECIAL = {
+  getBenefit() {
+    const discountAmount = 1_000;
+    return {
+      amount: 1,
+      price: discountAmount,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.SPECIAL,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ isSpecialDate }) {
+    return isSpecialDate === true;
+  },
+};
+
+export const GIFT = {
+  getBenefit() {
+    return {
+      menu: '샴페인',
+      amount: 1,
+      price: 25_000,
+    };
+  },
+
+  getEvent() {
+    return {
+      name: EVENT_NAMES.GIFT,
+      getBenefit: this.getBenefit,
+    };
+  },
+
+  isEventAvailable({ totalPrice }) {
+    return totalPrice >= 120_000;
+  },
+};
+
+export const ALL_EVENTS = Object.freeze({
+  CHRISTMAS_D_DAY,
+  WEEKDAY,
+  WEEKEND,
+  SPECIAL,
+  GIFT,
+});

리뷰: 매직 넘버를 사용하시는 것 같으신데요, 혹시 본인만에 기준이 있으실까요? 이곳에서만 따로 분리를 하지 않으신 것 같아서요.
@@ -0,0 +1,47 @@
+import { Console } from '@woowacourse/mission-utils';
+import MESSAGES from '../constants/messages.js';
+
+const OutputView = {
+  printResult(msgObj, result) {
+    const { title, printMsg } = msgObj;
+
+    Console.print(title);
+    Console.print(printMsg(result));
+  },
+
+  printStart() {
+    Console.print(MESSAGES.outputs.sayHi);
+  },
+
+  printMenus({ visitDate, menus }) {
+    Console.print(MESSAGES.outputs.eventPreview(visitDate));
+
+    this.printResult(MESSAGES.outputs.menus, menus);
+  },
+
+  printOriginalPrice(price) {
+    this.printResult(MESSAGES.outputs.originalPrice, price);
+  },
+
+  printGift(gift) {
+    this.printResult(MESSAGES.outputs.gift, gift);
+  },
+
+  printBenefits(benefits) {
+    this.printResult(MESSAGES.outputs.benefits, benefits);
+  },
+
+  printTotalBenefitMoney(money) {
+    this.printResult(MESSAGES.outputs.totalBenefitMoney, money);
+  },
+
+  printPayment(money) {
+    this.printResult(MESSAGES.outputs.payment, money);
+  },
+
+  printBadge(badge) {
+    this.printResult(MESSAGES.outputs.badge, badge);
+  },
+};
+
+export default OutputView;

리뷰: 이런식으로 보내면 조금 더 깔끔해지는군요...!!!
@@ -0,0 +1,94 @@
+import OrderItem from './OrderItem.js';
+
+import MESSAGES from '../constants/messages.js';
+
+import throwError from '../utils/throwError.js';
+import {
+  hasDuplicatedMenu,
+  hasOnlyBeverages,
+  isTotalAmountOfMenusValid,
+} from '../utils/validators.js';
+
+class Receipt {
+  #orders;
+
+  #orderItems;
+
+  constructor(orders) {
+    this.#validate(orders);
+    this.#orders = orders;
+    this.#orderItems = [];
+  }
+
+  #validate(orders) {
+    if (!isTotalAmountOfMenusValid(orders))
+      throwError(MESSAGES.errors.invalidOrders);
+
+    if (hasDuplicatedMenu(orders)) throwError(MESSAGES.errors.invalidOrders);
+
+    if (hasOnlyBeverages(orders)) throwError(MESSAGES.errors.invalidOrders);
+  }
+
+  generateOrders() {
+    this.#orderItems = this.#orders.map(
+      ({ menu, amount }) => new OrderItem(menu, amount),
+    );
+  }
+
+  get totalPrice() {
+    return this.#orderItems.reduce(
+      (totalPrice, orderItem) => totalPrice + orderItem.totalPrice,
+      0,
+    );
+  }
+
+  get receipt() {
+    const receipt = {};
+
+    this.#orderItems.forEach((orderItem) => {
+      const { category, menu, amount } = orderItem.item;
+
+      if (!Array.isArray(receipt[category])) {
+        receipt[category] = [];
+      }
+
+      receipt[category].push({ menu, amount });
+    });
+
+    return receipt;
+  }
+
+  get orderCategories() {
+    const categories = new Set();
+
+    this.#orderItems.forEach((orderItem) => {
+      const { category } = orderItem.item;
+      categories.add(category);
+    });
+
+    return [...categories];
+  }
+
+  get orderCntByCategory() {
+    const orderCnt = {};
+
+    this.#orderItems.forEach((orderItem) => {
+      const { category, amount } = orderItem.item;
+
+      if (!orderCnt[category]) orderCnt[category] = 0;
+
+      orderCnt[category] += amount;
+    });
+
+    return orderCnt;
+  }
+
+  get menus() {
+    return this.#orderItems.map((orderItem) => {
+      const { menu, amount } = orderItem.item;
+      return { menu, amount };
+    });
+  }
+}
+
+export default Receipt;

리뷰: get의 사용법 배우고 갑니다...!
@@ -0,0 +1,46 @@
+import MESSAGES from '../constants/messages.js';
+import { CATEGORIES, MENUS } from '../constants/menus.js';
+
+import { getValueOfField } from '../utils/object.js';
+import throwError from '../utils/throwError.js';
+import { isMenuExists } from '../utils/validators.js';
+
+class OrderItem {
+  #category;
+
+  #menu;
+
+  #amount;
+
+  constructor(menu, amount) {
+    this.#validate(menu);
+    this.#setCategory(menu);
+    this.#menu = menu;
+    this.#amount = amount;
+  }
+
+  #validate(menu) {
+    if (!isMenuExists(menu)) throwError(MESSAGES.errors.invalidMenu);
+  }
+
+  #setCategory(menu) {
+    this.#category = CATEGORIES.find((category) =>
+      getValueOfField(MENUS, `${category}.${menu}`),
+    );
+  }
+
+  get totalPrice() {
+    const price = getValueOfField(MENUS, `${this.#category}.${this.#menu}`);
+    return price * this.#amount;
+  }
+
+  get item() {
+    return {
+      category: this.#category,
+      menu: this.#menu,
+      amount: this.#amount,
+    };
+  }
+}
+
+export default OrderItem;

리뷰: get set 함수를 이렇게 지정할 수 있다는 걸 처음 알게되었네요!
@@ -0,0 +1,38 @@
+/**
+ * 두 객체가 같은 값을 가지고 있는지 얕게 비교
+ * @param {object} obj1
+ * @param {object} obj2
+ */
+export const shallowEqual = (objA, objB) => {
+  let result = true;
+
+  // 두 객체의 key 개수 비교
+  const keysA = Object.keys(objA);
+  const keysB = Object.keys(objB);
+  if (keysA.length !== keysB.length) result = false;
+
+  // 두 객체의 value 값 비교
+  keysA.forEach((key) => {
+    if (objA[key] !== objB[key]) result = false;
+  });
+
+  return result;
+};
+
+/**
+ * 점 표기법(.)을 사용해서 중첩 객체의 값을 찾는 함수
+ * 참고: https://elvanov.com/2286
+ * @param {object} obj
+ * @param {string} field
+ */
+export const getValueOfField = (obj, field) => {
+  if (!field) {
+    return null;
+  }
+
+  const keys = field.split('.');
+
+  return keys.reduce((curObj, curKey) => (curObj ? curObj[curKey] : null), obj);
+};
+
+export const isEmptyObject = (obj) => JSON.stringify(obj) === '{}';

리뷰: 내용 잘 봤습니다 ㅎㅎ