ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,71 @@
+package store.product.promotion;
+
+
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+
+public class PromotionResult {
+
+    private int appliedItemCount = 0;
+    private int omittedItemCount = 0;
+    private int totalItemCount = 0;
+    private PromotionState state;
+    private String productName;
+
+    public PromotionResult(){
+
+    }
+
+    public PromotionResult(PromotionState state, int totalItemCount,int appliedItemCount, int omittedItemCount, String productName){
+        this.state = state;
+        this.totalItemCount = totalItemCount;
+        this.appliedItemCount = appliedItemCount;
+        this.omittedItemCount = omittedItemCount;
+        this.productName = productName;
+
+    }
+
+//    public void setAppliedItemCount(int appliedItemCount) {
+//        this.appliedItemCount = appliedItemCount;
+//    }
+//
+//    public void setNeededItemCount(int enableItemCount) {
+//        this.omittedItemCount = enableItemCount;
+//    }
+
+    public int getAppliedItemCount() {
+        return appliedItemCount;
+    }
+
+    public int getOmittedItemCount() {
+        return omittedItemCount;
+    }
+
+    public int getTotalItemCount() { return totalItemCount;}
+
+    public int getNonPromotedCount() {
+        int fullPromotedCount = totalItemCount + omittedItemCount;
+        int appliedCountWhenFullPromoted = appliedItemCount + 1;
+        int zero = 0;
+        if(fullPromotedCount% appliedCountWhenFullPromoted != zero){
+            ExceptionFactory.throwIllegalStateException(ExceptionType.INTERNAL_ERROR);
+        }
+        int promotionUnit = fullPromotedCount/appliedCountWhenFullPromoted;
+        return totalItemCount % promotionUnit;
+    }
+
+    public PromotionState getState() { return state; }
+
+    public String getProductName() {return  productName;}
+
+    public PromotionResult transitState(PromotionState newState){
+        return new PromotionResult(newState,totalItemCount,appliedItemCount,omittedItemCount,productName);
+    }
+
+    static public PromotionResult createNoPromotion(String productName,int totalItemCount){
+        final int zero = 0;
+        return new PromotionResult(PromotionState.NO_PROMOTION,totalItemCount,zero,zero,productName);
+    }
+
+
+}

리뷰: 저는 메서드 바디가 한 줄이어도 개행을 해주는 것이 가독성에 좋다고 생각합니다! @armcortex3445 님 의견은 어떠신가요?

그리고 공백도 조금 더 신경써주시면 가독성이 더 좋아질 것 같다고 생각합니다!

```java
public PromotionState getState() {
    return state;
}

public String getProductName() {
    return productName;
}
```
@@ -0,0 +1,10 @@
+package store.product.promotion;
+
+public enum PromotionState {
+    APPLIED,
+    OMISSION,
+
+    NO_PROMOTION,
+    INSUFFICIENT,
+    NONE;
+}

리뷰: Promotion의 상태를 이렇게 관리할 수도 있겠네요! 좋은 방법 알아갑니다👍
@@ -0,0 +1,80 @@
+package store;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import store.io.ProductFile;
+import store.io.PromotionFile;
+import store.product.Product;
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+import store.utils.Transformer;
+import store.utils.Validator;
+
+public class LoadModel {
+    public final static String PRODUCT_LIST_FORMAT = "name,price,quantity,promotion";
+    public final static String PROMOTION_LIST_FROMAT= "name,buy,get,start_date,end_date";
+    public final static String DELIMITER = "\n";
+    final static String RESOURCE_PATH = "./src/main/resources/";
+    final static String PRODUCT_LIST = "products.md";
+    final static String PROMOTION_LIST = "promotions.md";
+    public LoadModel(){
+    }
+
+    public String loadProductList(){
+        String result = readFileAsString(RESOURCE_PATH + PRODUCT_LIST);
+        validateProductList(result);
+        return result;
+    }
+
+    public String loadPromotionList(){
+        String result = readFileAsString(RESOURCE_PATH + PROMOTION_LIST);
+        validatePromotionList(result);
+        return result;
+    }
+
+    public List<String> readFile(String path){
+        Validator.validateFileSize(path);
+        try {
+            return Files.readAllLines(Paths.get(path));
+        } catch (IOException exception){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.READ_FILE_FAIL,exception);
+            throw new RuntimeException();
+        }
+    }
+
+    public String readFileAsString(String path){
+
+        List<String> contents = readFile(path);
+        if(contents.isEmpty()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        return Transformer.concatenateList(contents,DELIMITER);
+    }
+
+    public static void validateProductList(String products){
+        if(products.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> productList = Arrays.stream(products.split(DELIMITER)).toList();
+        if(!productList.getFirst().equals(PRODUCT_LIST_FORMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(productList, ProductFile.COLUMN_DELIMITER,ProductFile.values().length);
+    }
+
+    public static void validatePromotionList(String promotions){
+        if(promotions.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> promotionList = Arrays.stream(promotions.split(DELIMITER)).toList();
+        if(!promotionList.getFirst().equals(PROMOTION_LIST_FROMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(promotionList,PromotionFile.COLUMN_DELIMITER,PromotionFile.values().length);
+    }
+
+
+}

리뷰: 말씀하신 방법이 OS 플랫폼 독립적이어서 확장성과 재사용성 그리고 안정성이 높은 코드라 생각됩니다.
좋은 좋언 감사합니다.
@@ -0,0 +1,73 @@
+package store;
+
+public enum StoreViewMessage {
+
+    WELCOME("안녕하세요. W편의점입니다.\n"
+            + "현재 보유하고 있는 상품입니다."),
+    PURCHASE_GUIDE("구매하실 상품명과 수량을 입력해 주세요. (예: [사이다-2],[감자칩-1])"),
+    MEMBERSHIP_GUIDE("멤버십 할인을 받으시겠습니까? (Y/N)"),
+
+    RECEIPT_HEAD("==============W 편의점================"),
+    RECEIPT_HEAD_PROMOTION("=============증\t정==============="),
+    RECEIPT_HEAD_ACCOUNT("===================================="),
+    RETRY_PURCHASE("감사합니다. 구매하고 싶은 다른 상품이 있나요? (Y/N)"),
+
+    ERROR_INVALID_FORMAT("[ERROR] 올바르지 않은 형식으로 입력했습니다. 다시 입력해 주세요."),
+
+    ERROR_NOT_EXIST_PRODUCT("[ERROR] 존재하지 않는 상품입니다. 다시 입력해 주세요."),
+    ERROR_OVERFLOW_PURCHASE("[ERROR] 재고 수량을 초과하여 구매할 수 없습니다. 다시 입력해 주세요."),
+    ERROR_NO_COUNT_PRODUCT("[ERROR] 재고가 없는 상품입니다. 다시 입력해 주세요.");
+
+    private final String message;
+
+    static public final String PURCHASE_PATTERN = "\\[([a-zA-Z가-힣0-9]+)-(\\d+)]";
+    static public final String PURCHASE_LIST_DELIMITER = ",";
+    static public final String ANSWER_NO = "N";
+    static public final String ANSWER_YES = "Y";
+
+    private StoreViewMessage(String message){
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void printMessage(){
+        System.out.println(this.message);
+    }
+
+    public static void printReceiptFormat(String first, String second, String third){
+        final int FIRST_WIDTH = 15;
+        final int SECOND_WIDTH = 8;
+        final int THIRD_WIDTH = 10;
+        System.out.printf("%-" + FIRST_WIDTH + "s%-" + SECOND_WIDTH + "s%-" + THIRD_WIDTH + "s\n", first, second, third);
+    }
+
+    public static void printReceiptProductListHead(){
+        final String productNameColumn = "상품명";
+        final String countColumn = "수량";
+        final String priceColumn = "금액";
+        printReceiptFormat(productNameColumn,countColumn,priceColumn);
+    }
+
+    public static void printProduct(String ProductName, int price, int count, String promotionName){
+        final String format = "- %s %,d원 %d개 %s\n";
+        System.out.printf(format,ProductName,price,count,promotionName);
+    }
+
+    public static void printInsufficientProduct(String ProductName, int price, String promotionName){
+        final String format = "- %s %,d원 재고 없음 %s\n";
+        System.out.printf(format,ProductName,price,promotionName);
+    }
+
+    public static void printPromotionReturnAvailable(String productName){
+        String format = "현재 %s은(는) 1개를 무료로 더 받을 수 있습니다. 추가하시겠습니까? (Y/N)\n";
+        System.out.printf(format,productName);
+    }
+
+    public static void printPromotionWarning(String productName,int count) {
+        String format = "현재 %s %d개는 프로모션 할인이 적용되지 않습니다. 그래도 구매하시겠습니까? (Y/N)\n";
+        System.out.printf(format, productName, count);
+    }
+}

리뷰: 전역에서 사용할 목적으로 선언하였는데요. 
시간이 부족하여, 상수들과 상수 관련 기능을 다른 클래스로 옮기지 못하여 이런 코드가 되어버렸네요
@@ -0,0 +1,58 @@
+package store.product;
+
+import store.product.promotion.PromotionState;
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+import store.utils.Validator;
+
+public class PurchaseRequest {
+    private String productName;
+    private int countPurchased;
+    private PromotionState promotionState;
+    public PurchaseRequest(){
+
+    }
+
+    public PurchaseRequest(String productName, int countPurchased, PromotionState promotionState){
+        this.countPurchased = countPurchased;
+        this.productName = productName;
+        this.promotionState = promotionState;
+    }
+
+    public String getProductName(){
+        return this.productName;
+    }
+    public int getCountPurchased(){
+        return this.countPurchased;
+    }
+
+    public PromotionState getPromotionState(){
+        return this.promotionState;
+    }
+
+    public void increaseCount(int value){
+        Validator.validatePositiveNumber(value);
+        this.countPurchased += value;
+    }
+
+    public PurchaseRequest tryToIncrease(boolean isIncrease){
+        int step = 1;
+        if(isIncrease){
+            this.increaseCount(step);
+            return this;
+        }
+        return this;
+    }
+
+    public void decreaseCount(int value){
+        if(value > this.countPurchased){
+            ExceptionFactory.throwIllegalStateException(ExceptionType.INTERNAL_ERROR);
+        }
+        this.countPurchased -=value;
+    }
+
+    public boolean isCountMet(){
+        int zero = 0;
+        return this.countPurchased == zero;
+    }
+}

리뷰: PurchaseRequest는 DTO 역할과 구매 주문 데이터 저장 역할을 하는 클래스인데요.

DTO 역할을 위해서 다른 클래스에서도 쉽게 생성할 수 있도록, public을 사용하였습니다.
@@ -0,0 +1,71 @@
+package store.product.promotion;
+
+
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+
+public class PromotionResult {
+
+    private int appliedItemCount = 0;
+    private int omittedItemCount = 0;
+    private int totalItemCount = 0;
+    private PromotionState state;
+    private String productName;
+
+    public PromotionResult(){
+
+    }
+
+    public PromotionResult(PromotionState state, int totalItemCount,int appliedItemCount, int omittedItemCount, String productName){
+        this.state = state;
+        this.totalItemCount = totalItemCount;
+        this.appliedItemCount = appliedItemCount;
+        this.omittedItemCount = omittedItemCount;
+        this.productName = productName;
+
+    }
+
+//    public void setAppliedItemCount(int appliedItemCount) {
+//        this.appliedItemCount = appliedItemCount;
+//    }
+//
+//    public void setNeededItemCount(int enableItemCount) {
+//        this.omittedItemCount = enableItemCount;
+//    }
+
+    public int getAppliedItemCount() {
+        return appliedItemCount;
+    }
+
+    public int getOmittedItemCount() {
+        return omittedItemCount;
+    }
+
+    public int getTotalItemCount() { return totalItemCount;}
+
+    public int getNonPromotedCount() {
+        int fullPromotedCount = totalItemCount + omittedItemCount;
+        int appliedCountWhenFullPromoted = appliedItemCount + 1;
+        int zero = 0;
+        if(fullPromotedCount% appliedCountWhenFullPromoted != zero){
+            ExceptionFactory.throwIllegalStateException(ExceptionType.INTERNAL_ERROR);
+        }
+        int promotionUnit = fullPromotedCount/appliedCountWhenFullPromoted;
+        return totalItemCount % promotionUnit;
+    }
+
+    public PromotionState getState() { return state; }
+
+    public String getProductName() {return  productName;}
+
+    public PromotionResult transitState(PromotionState newState){
+        return new PromotionResult(newState,totalItemCount,appliedItemCount,omittedItemCount,productName);
+    }
+
+    static public PromotionResult createNoPromotion(String productName,int totalItemCount){
+        final int zero = 0;
+        return new PromotionResult(PromotionState.NO_PROMOTION,totalItemCount,zero,zero,productName);
+    }
+
+
+}

리뷰: 저도 동일한 의견인데요.
인텔리제이의 fomatter 설정 수정이 필요하겠네요.
@@ -0,0 +1,80 @@
+package store;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import store.io.ProductFile;
+import store.io.PromotionFile;
+import store.product.Product;
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+import store.utils.Transformer;
+import store.utils.Validator;
+
+public class LoadModel {
+    public final static String PRODUCT_LIST_FORMAT = "name,price,quantity,promotion";
+    public final static String PROMOTION_LIST_FROMAT= "name,buy,get,start_date,end_date";
+    public final static String DELIMITER = "\n";
+    final static String RESOURCE_PATH = "./src/main/resources/";
+    final static String PRODUCT_LIST = "products.md";
+    final static String PROMOTION_LIST = "promotions.md";
+    public LoadModel(){
+    }
+
+    public String loadProductList(){
+        String result = readFileAsString(RESOURCE_PATH + PRODUCT_LIST);
+        validateProductList(result);
+        return result;
+    }
+
+    public String loadPromotionList(){
+        String result = readFileAsString(RESOURCE_PATH + PROMOTION_LIST);
+        validatePromotionList(result);
+        return result;
+    }
+
+    public List<String> readFile(String path){
+        Validator.validateFileSize(path);
+        try {
+            return Files.readAllLines(Paths.get(path));
+        } catch (IOException exception){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.READ_FILE_FAIL,exception);
+            throw new RuntimeException();
+        }
+    }
+
+    public String readFileAsString(String path){
+
+        List<String> contents = readFile(path);
+        if(contents.isEmpty()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        return Transformer.concatenateList(contents,DELIMITER);
+    }
+
+    public static void validateProductList(String products){
+        if(products.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> productList = Arrays.stream(products.split(DELIMITER)).toList();
+        if(!productList.getFirst().equals(PRODUCT_LIST_FORMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(productList, ProductFile.COLUMN_DELIMITER,ProductFile.values().length);
+    }
+
+    public static void validatePromotionList(String promotions){
+        if(promotions.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> promotionList = Arrays.stream(promotions.split(DELIMITER)).toList();
+        if(!promotionList.getFirst().equals(PROMOTION_LIST_FROMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(promotionList,PromotionFile.COLUMN_DELIMITER,PromotionFile.values().length);
+    }
+
+
+}

리뷰: 위에 있는 메서드에서 `throw`를 하는데, `throw`를 한 번 더 하신 이유가 궁금합니다!
@@ -0,0 +1,47 @@
+package store.utils;
+
+public enum ExceptionType {
+    LIST_OVER_MAX_LENGTH("list is over mat length."),
+    INVALID_NUMERIC_STRING("String is not numeric."),
+    OUT_OF_RANGE_INT("number is out of int type rage"),
+    NON_POSITIVE_NUMBER("number is not positive number"),
+    NON_DIVISIBLE("values are not divisible relation"),
+    OUT_OF_SPECIFIC_RANGE("out of specific range"),
+    NEGATIVE_NUMBER("number is negative"),
+
+    //Number list  related
+    NOT_PROPER_SIZE("list size is not proper"),
+    DUPLICATED_ELEMENTS("list includes duplicated elements"),
+
+    //STRING related
+    EMPTY_STRING("string is empty"),
+    DISABLE_ENCODED_TO_UTF8("string is not able to be encoded by utf 8"),
+    INVALID_INPUT_STRING_FORMAT("input string format is invalid"),
+    INVALID_NAME_FORMAT("name should be composed by english, korean and number"),
+
+    //Model
+    INTERNAL_ERROR("Internal logic error"),
+
+    //Promotion
+    INVALID_RETURN_PROMOTION("return should be 1"),
+
+    //File or I/O
+    READ_FILE_FAIL("can't read the file"),
+    TOO_LARGE_FILE("File is too large to process"),
+    EMPTY_FILE("File is empty"),
+    INVALID_FILE_FORMAT("File format is invalid"),
+
+    //LocalDate
+    INVALID_DATE_STRING("String is not able to pared to LocalDate/LocalDateTime");
+
+    private final String message;
+
+    private ExceptionType(String message){
+        this.message = message;
+    }
+
+    public String getMessage(){
+        return this.message;
+    }
+
+}

리뷰: 다양한 예외를 처리하신 부분이 인상적입니다!
@@ -0,0 +1,80 @@
+package store;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import store.io.ProductFile;
+import store.io.PromotionFile;
+import store.product.Product;
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+import store.utils.Transformer;
+import store.utils.Validator;
+
+public class LoadModel {
+    public final static String PRODUCT_LIST_FORMAT = "name,price,quantity,promotion";
+    public final static String PROMOTION_LIST_FROMAT= "name,buy,get,start_date,end_date";
+    public final static String DELIMITER = "\n";
+    final static String RESOURCE_PATH = "./src/main/resources/";
+    final static String PRODUCT_LIST = "products.md";
+    final static String PROMOTION_LIST = "promotions.md";
+    public LoadModel(){
+    }
+
+    public String loadProductList(){
+        String result = readFileAsString(RESOURCE_PATH + PRODUCT_LIST);
+        validateProductList(result);
+        return result;
+    }
+
+    public String loadPromotionList(){
+        String result = readFileAsString(RESOURCE_PATH + PROMOTION_LIST);
+        validatePromotionList(result);
+        return result;
+    }
+
+    public List<String> readFile(String path){
+        Validator.validateFileSize(path);
+        try {
+            return Files.readAllLines(Paths.get(path));
+        } catch (IOException exception){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.READ_FILE_FAIL,exception);
+            throw new RuntimeException();
+        }
+    }
+
+    public String readFileAsString(String path){
+
+        List<String> contents = readFile(path);
+        if(contents.isEmpty()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        return Transformer.concatenateList(contents,DELIMITER);
+    }
+
+    public static void validateProductList(String products){
+        if(products.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> productList = Arrays.stream(products.split(DELIMITER)).toList();
+        if(!productList.getFirst().equals(PRODUCT_LIST_FORMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(productList, ProductFile.COLUMN_DELIMITER,ProductFile.values().length);
+    }
+
+    public static void validatePromotionList(String promotions){
+        if(promotions.isBlank()) {
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.EMPTY_FILE);
+        }
+        List<String> promotionList = Arrays.stream(promotions.split(DELIMITER)).toList();
+        if(!promotionList.getFirst().equals(PROMOTION_LIST_FROMAT)){
+            ExceptionFactory.throwIllegalArgumentException(ExceptionType.INVALID_FILE_FORMAT);
+        }
+        Validator.validateEachLine(promotionList,PromotionFile.COLUMN_DELIMITER,PromotionFile.values().length);
+    }
+
+
+}

리뷰: 사소한 부분이지만, 오타가 있는 거 같아요!
`PROMOTION_LIST_FROMAT`을 `PROMOTION_LIST_FORMAT`으로 바꾸시면 좋을 거 같아요!
@@ -0,0 +1,26 @@
+package store.utils;
+
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class TransformerTest {
+
+
+    @Test
+    void testJoinToString(){
+        assertThat(Transformer.joinToString(List.of(1,2,3,4,5),", ")).isEqualTo("1, 2, 3, 4, 5");
+        assertThat(Transformer.joinToString(List.of(1,2,3,4,5),"-")).isEqualTo("1-2-3-4-5");
+    }
+
+    @Test
+    void testParsePositiveInt(){
+        assertThat(Transformer.parsePositiveInt("1000")).isEqualTo(1000);
+        assertThatThrownBy(()->Transformer.parsePositiveInt("?")).isInstanceOf(IllegalArgumentException.class);
+        assertThatThrownBy(()->Transformer.parsePositiveInt("")).isInstanceOf(IllegalArgumentException.class);
+    }
+
+}

리뷰: 꼼꼼한 테스트가 인상적입니다!
다른 부분에서는 `@ParameterizedTest`를 잘 사용하셨는데, 이 부분은 사용하지 않으신 이유가 궁금합니다!
혹시나 `List`같은 부분을 `@ValueSource`로 못 받아서 그러셨다면, `MethodSource`에 대해 알아보시면 좋을 거 같아요!
@@ -0,0 +1,58 @@
+package store.product;
+
+import store.product.promotion.PromotionState;
+import store.utils.ExceptionFactory;
+import store.utils.ExceptionType;
+import store.utils.Validator;
+
+public class PurchaseRequest {
+    private String productName;
+    private int countPurchased;
+    private PromotionState promotionState;
+    public PurchaseRequest(){
+
+    }
+
+    public PurchaseRequest(String productName, int countPurchased, PromotionState promotionState){
+        this.countPurchased = countPurchased;
+        this.productName = productName;
+        this.promotionState = promotionState;
+    }
+
+    public String getProductName(){
+        return this.productName;
+    }
+    public int getCountPurchased(){
+        return this.countPurchased;
+    }
+
+    public PromotionState getPromotionState(){
+        return this.promotionState;
+    }
+
+    public void increaseCount(int value){
+        Validator.validatePositiveNumber(value);
+        this.countPurchased += value;
+    }
+
+    public PurchaseRequest tryToIncrease(boolean isIncrease){
+        int step = 1;
+        if(isIncrease){
+            this.increaseCount(step);
+            return this;
+        }
+        return this;
+    }
+
+    public void decreaseCount(int value){
+        if(value > this.countPurchased){
+            ExceptionFactory.throwIllegalStateException(ExceptionType.INTERNAL_ERROR);
+        }
+        this.countPurchased -=value;
+    }
+
+    public boolean isCountMet(){
+        int zero = 0;
+        return this.countPurchased == zero;
+    }
+}

리뷰: 아래 부분에서 `return this;`를 해서 이 부분은 없어도 될 거 같아요!