diff --git a/src/main/java/cleancode/studycafe/tobe/StudyCafeApplication.java b/src/main/java/cleancode/studycafe/tobe/StudyCafeApplication.java index a60afb3f3..5ad06e52c 100644 --- a/src/main/java/cleancode/studycafe/tobe/StudyCafeApplication.java +++ b/src/main/java/cleancode/studycafe/tobe/StudyCafeApplication.java @@ -1,9 +1,14 @@ package cleancode.studycafe.tobe; +import cleancode.studycafe.tobe.io.StudyCafeFileHandler; +import cleancode.studycafe.tobe.model.StudyCafePassRepository; + public class StudyCafeApplication { public static void main(String[] args) { - StudyCafePassMachine studyCafePassMachine = new StudyCafePassMachine(); + StudyCafeFileHandler studyCafeFileHandler = new StudyCafeFileHandler(); + StudyCafePassRepository repository = StudyCafePassRepository.from(studyCafeFileHandler); + StudyCafePassMachine studyCafePassMachine = new StudyCafePassMachine(repository); studyCafePassMachine.run(); } diff --git a/src/main/java/cleancode/studycafe/tobe/StudyCafePassMachine.java b/src/main/java/cleancode/studycafe/tobe/StudyCafePassMachine.java index 3d34d9eef..c399993dd 100644 --- a/src/main/java/cleancode/studycafe/tobe/StudyCafePassMachine.java +++ b/src/main/java/cleancode/studycafe/tobe/StudyCafePassMachine.java @@ -3,10 +3,7 @@ import cleancode.studycafe.tobe.exception.AppException; import cleancode.studycafe.tobe.io.InputHandler; import cleancode.studycafe.tobe.io.OutputHandler; -import cleancode.studycafe.tobe.io.StudyCafeFileHandler; -import cleancode.studycafe.tobe.model.StudyCafeLockerPass; -import cleancode.studycafe.tobe.model.StudyCafePass; -import cleancode.studycafe.tobe.model.StudyCafePassType; +import cleancode.studycafe.tobe.model.*; import java.util.List; @@ -14,63 +11,31 @@ public class StudyCafePassMachine { private final InputHandler inputHandler = new InputHandler(); private final OutputHandler outputHandler = new OutputHandler(); + private final StudyCafePassRepository passRepository; + + public StudyCafePassMachine(StudyCafePassRepository passRepository) { + this.passRepository = passRepository; + } public void run() { try { outputHandler.showWelcomeMessage(); outputHandler.showAnnouncement(); - outputHandler.askPassTypeSelection(); - StudyCafePassType studyCafePassType = inputHandler.getPassTypeSelectingUserAction(); - if (studyCafePassType == StudyCafePassType.HOURLY) { - StudyCafeFileHandler studyCafeFileHandler = new StudyCafeFileHandler(); - List studyCafePasses = studyCafeFileHandler.readStudyCafePasses(); - List hourlyPasses = studyCafePasses.stream() - .filter(studyCafePass -> studyCafePass.getPassType() == StudyCafePassType.HOURLY) - .toList(); - outputHandler.showPassListForSelection(hourlyPasses); - StudyCafePass selectedPass = inputHandler.getSelectPass(hourlyPasses); - outputHandler.showPassOrderSummary(selectedPass, null); - } else if (studyCafePassType == StudyCafePassType.WEEKLY) { - StudyCafeFileHandler studyCafeFileHandler = new StudyCafeFileHandler(); - List studyCafePasses = studyCafeFileHandler.readStudyCafePasses(); - List weeklyPasses = studyCafePasses.stream() - .filter(studyCafePass -> studyCafePass.getPassType() == StudyCafePassType.WEEKLY) - .toList(); - outputHandler.showPassListForSelection(weeklyPasses); - StudyCafePass selectedPass = inputHandler.getSelectPass(weeklyPasses); - outputHandler.showPassOrderSummary(selectedPass, null); - } else if (studyCafePassType == StudyCafePassType.FIXED) { - StudyCafeFileHandler studyCafeFileHandler = new StudyCafeFileHandler(); - List studyCafePasses = studyCafeFileHandler.readStudyCafePasses(); - List fixedPasses = studyCafePasses.stream() - .filter(studyCafePass -> studyCafePass.getPassType() == StudyCafePassType.FIXED) - .toList(); - outputHandler.showPassListForSelection(fixedPasses); - StudyCafePass selectedPass = inputHandler.getSelectPass(fixedPasses); + //입장권 조회 + StudyCafePassType studyCafePassType = inputHandler.getPassTypeSelectingUserAction(); + List hourlyPasses = passRepository.find(studyCafePassType); - List lockerPasses = studyCafeFileHandler.readLockerPasses(); - StudyCafeLockerPass lockerPass = lockerPasses.stream() - .filter(option -> - option.getPassType() == selectedPass.getPassType() - && option.getDuration() == selectedPass.getDuration() - ) - .findFirst() - .orElse(null); + //입장권 선택 + outputHandler.showPassListForSelection(hourlyPasses); + StudyCafePass selectedPass = inputHandler.getSelectPass(hourlyPasses); - boolean lockerSelection = false; - if (lockerPass != null) { - outputHandler.askLockerPass(lockerPass); - lockerSelection = inputHandler.getLockerSelection(); - } + //사물함 이용 + askForUsingLockerPass(selectedPass); - if (lockerSelection) { - outputHandler.showPassOrderSummary(selectedPass, lockerPass); - } else { - outputHandler.showPassOrderSummary(selectedPass, null); - } - } + //금액 출력 + outputHandler.showPassOrderSummary(selectedPass); } catch (AppException e) { outputHandler.showSimpleMessage(e.getMessage()); } catch (Exception e) { @@ -78,4 +43,12 @@ public void run() { } } + private void askForUsingLockerPass(StudyCafePass pass) { + assert pass != null; + if (pass.isNotUsingLocker()) return; + outputHandler.askLockerPass(pass); + if (inputHandler.getLockerSelection()) { + pass.selectLocker(); + } + } } diff --git a/src/main/java/cleancode/studycafe/tobe/io/OutputHandler.java b/src/main/java/cleancode/studycafe/tobe/io/OutputHandler.java index d8e0181a4..a77c69746 100644 --- a/src/main/java/cleancode/studycafe/tobe/io/OutputHandler.java +++ b/src/main/java/cleancode/studycafe/tobe/io/OutputHandler.java @@ -1,6 +1,5 @@ package cleancode.studycafe.tobe.io; -import cleancode.studycafe.tobe.model.StudyCafeLockerPass; import cleancode.studycafe.tobe.model.StudyCafePass; import java.util.List; @@ -27,36 +26,30 @@ public void showPassListForSelection(List passes) { System.out.println("이용권 목록"); for (int index = 0; index < passes.size(); index++) { StudyCafePass pass = passes.get(index); - System.out.println(String.format("%s. ", index + 1) + pass.display()); + System.out.println(String.format("%s. ", index + 1) + pass.getMenuString()); } } - public void askLockerPass(StudyCafeLockerPass lockerPass) { + public void askLockerPass(StudyCafePass pass) { System.out.println(); String askMessage = String.format( - "사물함을 이용하시겠습니까? (%s)", - lockerPass.display() + "사물함을 이용하시겠습니까? (%s)", + pass.getLockerMenuString() ); System.out.println(askMessage); System.out.println("1. 예 | 2. 아니오"); } - public void showPassOrderSummary(StudyCafePass selectedPass, StudyCafeLockerPass lockerPass) { + public void showPassOrderSummary(StudyCafePass selectedPass) { + assert selectedPass != null; System.out.println(); System.out.println("이용 내역"); - System.out.println("이용권: " + selectedPass.display()); - if (lockerPass != null) { - System.out.println("사물함: " + lockerPass.display()); + System.out.println("이용권: " + selectedPass.getMenuString()); + if (selectedPass.isLockerSelected()) { + System.out.println("사물함: " + selectedPass.getLockerMenuString()); } - - double discountRate = selectedPass.getDiscountRate(); - int discountPrice = (int) (selectedPass.getPrice() * discountRate); - if (discountPrice > 0) { - System.out.println("이벤트 할인 금액: " + discountPrice + "원"); - } - - int totalPrice = selectedPass.getPrice() - discountPrice + (lockerPass != null ? lockerPass.getPrice() : 0); + int totalPrice = selectedPass.getTotalPrice(); System.out.println("총 결제 금액: " + totalPrice + "원"); System.out.println(); } @@ -64,5 +57,4 @@ public void showPassOrderSummary(StudyCafePass selectedPass, StudyCafeLockerPass public void showSimpleMessage(String message) { System.out.println(message); } - } diff --git a/src/main/java/cleancode/studycafe/tobe/io/StudyCafeFileHandler.java b/src/main/java/cleancode/studycafe/tobe/io/StudyCafeFileHandler.java index 920a27e59..b356d2d77 100644 --- a/src/main/java/cleancode/studycafe/tobe/io/StudyCafeFileHandler.java +++ b/src/main/java/cleancode/studycafe/tobe/io/StudyCafeFileHandler.java @@ -2,52 +2,34 @@ import cleancode.studycafe.tobe.model.StudyCafeLockerPass; import cleancode.studycafe.tobe.model.StudyCafePass; -import cleancode.studycafe.tobe.model.StudyCafePassType; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; public class StudyCafeFileHandler { public List readStudyCafePasses() { + List lockerPasses = readLockerPasses(); try { List lines = Files.readAllLines(Paths.get("src/main/resources/cleancode/studycafe/pass-list.csv")); - List studyCafePasses = new ArrayList<>(); - for (String line : lines) { - String[] values = line.split(","); - StudyCafePassType studyCafePassType = StudyCafePassType.valueOf(values[0]); - int duration = Integer.parseInt(values[1]); - int price = Integer.parseInt(values[2]); - double discountRate = Double.parseDouble(values[3]); - - StudyCafePass studyCafePass = StudyCafePass.of(studyCafePassType, duration, price, discountRate); - studyCafePasses.add(studyCafePass); - } - - return studyCafePasses; + return lines.stream().map(line -> line.split(",")) + .map(values -> { + int duration = Integer.parseInt(values[1]); + StudyCafeLockerPass locker = lockerPasses.stream().filter((lockerPass -> lockerPass.isCompatible(duration))).findFirst().orElse(null); + return StudyCafePass.of(values, locker); + }).toList(); } catch (IOException e) { throw new RuntimeException("파일을 읽는데 실패했습니다.", e); } } - public List readLockerPasses() { + private List readLockerPasses() { try { List lines = Files.readAllLines(Paths.get("src/main/resources/cleancode/studycafe/locker.csv")); - List lockerPasses = new ArrayList<>(); - for (String line : lines) { - String[] values = line.split(","); - StudyCafePassType studyCafePassType = StudyCafePassType.valueOf(values[0]); - int duration = Integer.parseInt(values[1]); - int price = Integer.parseInt(values[2]); - - StudyCafeLockerPass lockerPass = StudyCafeLockerPass.of(studyCafePassType, duration, price); - lockerPasses.add(lockerPass); - } - - return lockerPasses; + return lines.stream().map(line -> line.split(",")) + .map(StudyCafeLockerPass::fromValues).toList(); } catch (IOException e) { throw new RuntimeException("파일을 읽는데 실패했습니다.", e); } diff --git a/src/main/java/cleancode/studycafe/tobe/model/FixedStudyCafePass.java b/src/main/java/cleancode/studycafe/tobe/model/FixedStudyCafePass.java new file mode 100644 index 000000000..2db336b43 --- /dev/null +++ b/src/main/java/cleancode/studycafe/tobe/model/FixedStudyCafePass.java @@ -0,0 +1,35 @@ +package cleancode.studycafe.tobe.model; + +class FixedStudyCafePass extends StudyCafePass{ + private final StudyCafeLockerPass lockerPass; + protected FixedStudyCafePass(int duration, int price, double discountRate, StudyCafeLockerPass lockerPass) { + super(StudyCafePassType.FIXED, duration, price, discountRate); + this.lockerPass = lockerPass; + } + + + @Override + public boolean isNotUsingLocker() { + return false; + } + + @Override + public int getLockerPrice() { + return lockerPass.getPrice(); + } + + @Override + public String getLockerMenuString() { + return lockerPass.toMenuString(); + } + + @Override + public void selectLocker() { + lockerPass.select(); + } + + @Override + public boolean isLockerSelected() { + return lockerPass.isSelected(); + } +} diff --git a/src/main/java/cleancode/studycafe/tobe/model/HourlyStudyCafePass.java b/src/main/java/cleancode/studycafe/tobe/model/HourlyStudyCafePass.java new file mode 100644 index 000000000..09a7f5ab6 --- /dev/null +++ b/src/main/java/cleancode/studycafe/tobe/model/HourlyStudyCafePass.java @@ -0,0 +1,7 @@ +package cleancode.studycafe.tobe.model; + +class HourlyStudyCafePass extends StudyCafePass{ + protected HourlyStudyCafePass(int duration, int price, double discountRate) { + super(StudyCafePassType.HOURLY, duration, price, discountRate); + } +} diff --git a/src/main/java/cleancode/studycafe/tobe/model/StudyCafeLockerPass.java b/src/main/java/cleancode/studycafe/tobe/model/StudyCafeLockerPass.java index 6512ec0a8..44eb8a782 100644 --- a/src/main/java/cleancode/studycafe/tobe/model/StudyCafeLockerPass.java +++ b/src/main/java/cleancode/studycafe/tobe/model/StudyCafeLockerPass.java @@ -2,43 +2,42 @@ public class StudyCafeLockerPass { - private final StudyCafePassType passType; private final int duration; private final int price; + private boolean selected; - private StudyCafeLockerPass(StudyCafePassType passType, int duration, int price) { - this.passType = passType; + private StudyCafeLockerPass(int duration, int price) { this.duration = duration; this.price = price; } - public static StudyCafeLockerPass of(StudyCafePassType passType, int duration, int price) { - return new StudyCafeLockerPass(passType, duration, price); + private static StudyCafeLockerPass of(int duration, int price) { + return new StudyCafeLockerPass(duration, price); } - public StudyCafePassType getPassType() { - return passType; + public static StudyCafeLockerPass fromValues(String[] values) { + int duration = Integer.parseInt(values[1]); + int price = Integer.parseInt(values[2]); + return StudyCafeLockerPass.of(duration, price); } - public int getDuration() { - return duration; + int getPrice() { + return selected ? price : 0; } - public int getPrice() { - return price; + public boolean isCompatible(int passDuration) { + return duration == passDuration; } - public String display() { - if (passType == StudyCafePassType.HOURLY) { - return String.format("%s시간권 - %d원", duration, price); - } - if (passType == StudyCafePassType.WEEKLY) { - return String.format("%s주권 - %d원", duration, price); - } - if (passType == StudyCafePassType.FIXED) { - return String.format("%s주권 - %d원", duration, price); - } - return ""; + void select() { + selected = true; } + boolean isSelected() { + return selected; + } + + String toMenuString() { + return StudyCafePassType.FIXED.toMenuString(duration, price); + } } diff --git a/src/main/java/cleancode/studycafe/tobe/model/StudyCafePass.java b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePass.java index 0749f41b8..4cd2122c5 100644 --- a/src/main/java/cleancode/studycafe/tobe/model/StudyCafePass.java +++ b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePass.java @@ -1,49 +1,77 @@ package cleancode.studycafe.tobe.model; -public class StudyCafePass { +public abstract class StudyCafePass { private final StudyCafePassType passType; private final int duration; private final int price; private final double discountRate; - private StudyCafePass(StudyCafePassType passType, int duration, int price, double discountRate) { + protected StudyCafePass(StudyCafePassType passType, int duration, int price, double discountRate) { this.passType = passType; this.duration = duration; this.price = price; this.discountRate = discountRate; } - public static StudyCafePass of(StudyCafePassType passType, int duration, int price, double discountRate) { - return new StudyCafePass(passType, duration, price, discountRate); + private static StudyCafePass weeklyOf(int duration, int price, double discountRate) { + return new WeeklyStudyCafePass(duration, price, discountRate); + } + + private static StudyCafePass hourlyOf(int duration, int price, double discountRate) { + return new HourlyStudyCafePass(duration, price, discountRate); + } + + private static StudyCafePass fixedOf(int duration, int price, double discountRate, StudyCafeLockerPass lockerPass) { + return new FixedStudyCafePass(duration, price, discountRate, lockerPass); + } + + public static StudyCafePass of(String[] values, StudyCafeLockerPass lockerPass) { + StudyCafePassType studyCafePassType = StudyCafePassType.valueOf(values[0]); + int duration = Integer.parseInt(values[1]); + int price = Integer.parseInt(values[2]); + double discountRate = Double.parseDouble(values[3]); + return switch (studyCafePassType) { + case HOURLY -> hourlyOf(duration, price, discountRate); + case WEEKLY -> weeklyOf(duration, price, discountRate); + case FIXED -> + fixedOf(duration, price, discountRate, lockerPass); + }; } public StudyCafePassType getPassType() { return passType; } - public int getDuration() { - return duration; + public int getTotalPrice() { + int discountPrice = (int) (price * discountRate); + if (discountPrice > 0) { + System.out.println("이벤트 할인 금액: " + discountPrice + "원"); + } + return price - discountPrice + getLockerPrice(); } - public int getPrice() { - return price; + public String getMenuString() { + return passType.toMenuString(duration, price); } - public double getDiscountRate() { - return discountRate; + // 3 케이스중 1개만 override 하므로 선정의 후 override + public boolean isLockerSelected() { + return false; } - public String display() { - if (passType == StudyCafePassType.HOURLY) { - return String.format("%s시간권 - %d원", duration, price); - } - if (passType == StudyCafePassType.WEEKLY) { - return String.format("%s주권 - %d원", duration, price); - } - if (passType == StudyCafePassType.FIXED) { - return String.format("%s주권 - %d원", duration, price); - } + public void selectLocker() { + } + + public boolean isNotUsingLocker() { + return true; + } + + public int getLockerPrice() { + return 0; + } + + public String getLockerMenuString() { return ""; } diff --git a/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassRepository.java b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassRepository.java new file mode 100644 index 000000000..64e58988f --- /dev/null +++ b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassRepository.java @@ -0,0 +1,24 @@ +package cleancode.studycafe.tobe.model; + +import cleancode.studycafe.tobe.io.StudyCafeFileHandler; + +import java.util.List; + +public class StudyCafePassRepository { + private final List passes; + + private StudyCafePassRepository(List passes) { + this.passes = passes; + } + + public List find(StudyCafePassType type) { + return passes.stream() + .filter(studyCafePass -> studyCafePass.getPassType() == type) + .toList(); + } + + public static StudyCafePassRepository from(StudyCafeFileHandler studyCafeFileHandler) { + List passes = studyCafeFileHandler.readStudyCafePasses(); + return new StudyCafePassRepository(passes); + } +} diff --git a/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassType.java b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassType.java index bac959b4f..73af45487 100644 --- a/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassType.java +++ b/src/main/java/cleancode/studycafe/tobe/model/StudyCafePassType.java @@ -1,15 +1,22 @@ package cleancode.studycafe.tobe.model; +import java.util.function.BiFunction; + public enum StudyCafePassType { - HOURLY("시간 단위 이용권"), - WEEKLY("주 단위 이용권"), - FIXED("1인 고정석"); + HOURLY("시간 단위 이용권", (Integer duration, Integer price) -> String.format("%s시간권 - %d원", duration, price)), + WEEKLY("주 단위 이용권", (Integer duration, Integer price) -> String.format("%s주권 - %d원", duration, price)), + FIXED("1인 고정석", (Integer duration, Integer price) -> String.format("%s주권 - %d원", duration, price)); private final String description; + private final BiFunction toMenu; - StudyCafePassType(String description) { + StudyCafePassType(String description, BiFunction calculator) { this.description = description; + this.toMenu = calculator; } + String toMenuString(Integer duration, Integer price) { + return toMenu.apply(duration, price); + } } diff --git a/src/main/java/cleancode/studycafe/tobe/model/WeeklyStudyCafePass.java b/src/main/java/cleancode/studycafe/tobe/model/WeeklyStudyCafePass.java new file mode 100644 index 000000000..55d713593 --- /dev/null +++ b/src/main/java/cleancode/studycafe/tobe/model/WeeklyStudyCafePass.java @@ -0,0 +1,7 @@ +package cleancode.studycafe.tobe.model; + +class WeeklyStudyCafePass extends StudyCafePass{ + protected WeeklyStudyCafePass(int duration, int price, double discountRate) { + super(StudyCafePassType.WEEKLY, duration, price, discountRate); + } +}