diff --git a/README.md b/README.md index bd90ef0247..9a3fe4af43 100644 --- a/README.md +++ b/README.md @@ -1 +1,78 @@ -# java-calculator-precourse \ No newline at end of file +# java-calculator-precourse + +## πŸš€ κ΅¬ν˜„ν•  κΈ°λŠ₯ λͺ©λ‘ + +### ⌨️ μž…λ ₯ + +- [x] λ§μ…ˆν•  λ¬Έμžμ—΄μ„ μž…λ ₯λ°›λŠ” κΈ°λŠ₯을 κ΅¬ν˜„ν•œλ‹€. + - [x] λ§μ…ˆ λ¬Έμžμ—΄ μž…λ ₯ μ•ˆλ‚΄ λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•œλ‹€. + - [x] μ‚¬μš©μžλ‘œλΆ€ν„° λ§μ…ˆν•  λ¬Έμžμ—΄μ„ μž…λ ₯λ°›λŠ”λ‹€. + - [x] μž…λ ₯된 λ¬Έμžμ—΄μ„ κ²€μ¦ν•œλ‹€. + - [x] μˆ«μžκ°€ ν•˜λ‚˜λΌλ„ ν¬ν•¨λ˜μ–΄μžˆμ§€ μ•Šμ€ 경우, μ˜ˆμ™Έλ₯Ό λ°˜ν™˜ν•œλ‹€. + - [x] κΈ°λ³Έ κ΅¬λΆ„μž 쀑 ν•˜λ‚˜λΌλ„ ν¬ν•¨λ˜μ–΄μžˆμ§€ μ•Šμ€ 경우, μ˜ˆμ™Έλ₯Ό λ°˜ν™˜ν•œλ‹€. + - [x] μž…λ ₯된 λ¬Έμžμ—΄μ„ νŒŒμ‹± 및 μΆ”κ°€ κ²€μ¦ν•œλ‹€. + - [x] μž…λ ₯κ°’μ—μ„œ νŽΈλ¦¬ν•˜κ²Œ 숫자λ₯Ό μΆ”μΆœν•˜κΈ° μœ„ν•΄ μ „μ²˜λ¦¬λ₯Ό μ§„ν–‰ν•œλ‹€. + - [x] λ¬Έμžμ—΄μ— μ»€μŠ€ν…€ κ΅¬λΆ„μžκ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•œλ‹€. + - [x] λ¬Έμžμ—΄ μ•ž 뢀뢄에 μ»€μŠ€ν…€ κ΅¬λΆ„μžκ°€ μžˆλŠ” 경우, 이λ₯Ό λ”°λ‘œ μ €μž₯ν•œλ‹€. + - [x] μ»€μŠ€ν…€ κ΅¬λΆ„μžλ₯Ό λΊΈ λ¬Έμžμ—΄μ„ μž…λ ₯κ°’μœΌλ‘œ μ΅œμ’… μ €μž₯ν•œλ‹€. + - [x] λ¬Έμžμ—΄λ‘œλΆ€ν„° μˆ«μžλ“€μ„ μΆ”μΆœν•œλ‹€. + - [x] μ£Όμ–΄μ§„ λ¬Έμžμ—΄μ— κ΅¬λΆ„μžκ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•œλ‹€. + - [x] λ§Œμ•½ κ΅¬λΆ„μžκ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ” 경우, κ΅¬λΆ„μžλ₯Ό κΈ°μ€€μœΌλ‘œ λ¬Έμžμ—΄μ„ λΆ„λ¦¬ν•œλ‹€. + - [x] κ΅¬λΆ„μžλ₯Ό 톡해 λΆ„λ¦¬λœ 값이 빈 λ¬Έμžμ—΄μΌ 경우, 결과둜 0을 λ°˜ν™˜ν•œλ‹€. + - [x] κ΅¬λΆ„μžλ₯Ό 톡해 λΆ„λ¦¬λœ 값이 μˆ«μžκ°€ 아닐 경우, μ˜ˆμ™Έλ₯Ό λ°˜ν™˜ν•œλ‹€. + - [x] κ΅¬λΆ„μžλ₯Ό 톡해 λΆ„λ¦¬λœ 값이 음수일 경우, μ˜ˆμ™Έλ₯Ό λ°˜ν™˜ν•œλ‹€. + - [x] μ΅œμ’…μ μœΌλ‘œ λΆ„λ¦¬λœ μˆ«μžλ“€μ„ λ¦¬μŠ€νŠΈμ— μ €μž₯ν•œλ‹€. + +### πŸ–₯ 좜λ ₯ + +- [x] λ§μ…ˆ κ²°κ³Όλ₯Ό 좜λ ₯ν•œλ‹€. + - [x] "κ²°κ³Ό"λΌλŠ” λ¬Έμžμ—΄μ™€ λ§μ…ˆ κ²°κ³Όλ₯Ό ":" κ΅¬λΆ„μžλ₯Ό 톡해 κ΅¬λΆ„ν•œλ‹€. + +### βš™οΈ 둜직 + +- [x] λ¦¬μŠ€νŠΈμ— μ €μž₯된 μˆ«μžλ“€μ„ λ”ν•˜λŠ” κΈ°λŠ₯을 κ΅¬ν˜„ν•œλ‹€. + - [x] λ¦¬μŠ€νŠΈμ— μ €μž₯된 μˆ«μžλ“€μ„ λͺ¨λ‘ λ”ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. + +--- + +## πŸ› οΈ λ¦¬νŒ©ν† λ§ λͺ©λ‘ + +### 1️⃣ λͺ¨λ“  μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λŠ” μžˆλŠ” ν˜„ 검증 둜직 β†’ 더 λ§Žμ€ μ˜ˆμ™Έμ— λŒ€λΉ„ν•˜κΈ° μœ„ν•΄, 더 λ§Žμ€ 검증 λ©”μ„œλ“œ κ΅¬ν˜„ + +- [x] μ»€μŠ€ν…€ κ΅¬λΆ„μžμ— μ‹€μ œ μ΄μŠ€μΌ€μ΄ν”„ 문법("\")이 ν¬ν•¨λœ κ²½μš°μ— λŒ€ν•œ μ˜ˆμ™Έ 처리λ₯Ό μΆ”κ°€ν•œλ‹€. +- [x] μ»€μŠ€ν…€ κ΅¬λΆ„μžμ— μˆ«μžκ°€ ν¬ν•¨λ˜λŠ” κ²½μš°μ— λŒ€ν•œ μ˜ˆμ™Έ 처리λ₯Ό μΆ”κ°€ν•œλ‹€. +- [x] μ»€μŠ€ν…€ κ΅¬λΆ„μžκ°€ 빈 λ¬Έμžμ—΄("")일 κ²½μš°μ— λŒ€ν•œ μ˜ˆμ™Έ 처리λ₯Ό μΆ”κ°€ν•œλ‹€. +- [x] κ΅¬λΆ„μžμ— μ˜ν•΄ λΆ„λ¦¬λœ 값이 μˆ«μžκ°€ μ•„λ‹Œ κ²½μš°μ— λŒ€ν•œ μ˜ˆμ™Έ 처리λ₯Ό μΆ”κ°€ν•œλ‹€. + +### 2️⃣ μž…λ ₯κ°’ 검증과 νŒŒμ‹± 둜직이 ν˜Όμš©λ˜λŠ” 문제 λ°œμƒ β†’ ν™•μ‹€ν•˜κ²Œ μ±…μž„μ„ 뢄리 + +- [x] μž…λ ₯κ°’ 검증과 κ΄€λ ¨λœ λ©”μ„œλ“œλ“€μ€ λͺ¨λ‘ `InputValidator`μ—μ„œ κ΄€λ¦¬ν•˜λ„λ‘ μ΄λ™μ‹œν‚¨λ‹€. +- [x] μž…λ ₯κ°’ νŒŒμ‹± κ³Όμ •μ—μ„œ μ“°μ΄λŠ” 검증 λ©”μ„œλ“œλ“€μ€ `InputFilter` λ‚΄μ—μ„œ `InputValidator`λ₯Ό μ°Έμ‘°ν•˜μ—¬ μ‚¬μš©ν•˜λ„λ‘ μˆ˜μ •ν•œλ‹€. + +### 3️⃣ 맀직 λ„˜λ²„ 및 λ¦¬ν„°λŸ΄ μ‚¬μš©μœΌλ‘œ μΈν•œ μΆ”ν›„ μœ μ§€λ³΄μˆ˜μ—μ„œμ˜ 어렀움 μ˜ˆμƒ β†’ 클래슀 및 μƒμˆ˜λ‘œμ„œ 관리 + +- [x] μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό Enum을 톡해 μƒμˆ˜λ‘œ κ΄€λ¦¬ν•˜λ„λ‘ μˆ˜μ •ν•œλ‹€. +- [x] κ΅¬λΆ„μž λͺ©λ‘μ„ Enum을 톡해 μƒμˆ˜λ‘œ κ΄€λ¦¬ν•˜λ„λ‘ μˆ˜μ •ν•œλ‹€. + +### 4️⃣ 숫자 값듀이 각 객체와 λ©”μ„œλ“œλ₯Ό 거치며 변경될 μ—¬μ§€κ°€ 있음 β†’ λΆˆλ³€ κ°œλ… 적용 + +- [x] 숫자 값듀을 λ³€κ²½ν•  수 없도둝 `final` ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν•œλ‹€. +- [x] 숫자 리슀트λ₯Ό 전달할 λ–„, λΆˆλ³€ 리슀트둜 전달될 수 μžˆλ„λ‘ List.of λ˜λŠ” unmodifiableListλ₯Ό μ μš©ν•œλ‹€. + +### 5️⃣ μΈμŠ€ν„΄μŠ€ 관리가 μ—¬λŸ¬ 곳에 μ‚°μž¬λ˜μ–΄ 있음 β†’ λͺ¨λ“  μΈμŠ€ν„΄μŠ€λ₯Ό ν•œ κ³³μ—μ„œ 관리 + +- [x] 정적 ν΄λž˜μŠ€μ™€ 일반 클래슀의 ꡬ뢄을 λΆ„λͺ…νžˆ ν•˜κΈ° μœ„ν•΄ `InputValidator` 클래슀λ₯Ό μ œμ™Έν•œ λͺ¨λ“  클래슀λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•œλ‹€. +- [x] `ApplicationConfig` 클래슀λ₯Ό 톡해 μ—¬λŸ¬ 개의 μΈμŠ€ν„΄μŠ€λ₯Ό ν•œ κ³³μ—μ„œ κ΄€λ¦¬ν•œλ‹€. + +### 6️⃣ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ 단 2κ°œλ°–μ— μ—†λŠ” 상황 β†’ 더 λ§Žμ€ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μž‘μ„±ν•˜μ—¬ ν…ŒμŠ€νŠΈ μš©μ΄μ„± ν–₯상 + +- [ ] 각 μ˜ˆμ™Έ 상황에 λŒ€ν•œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μΆ”κ°€ν•œλ‹€. +- [ ] κ·Έ 외에 각 λ©”μ„œλ“œλ“€μ΄ μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜λŠ”μ§€ 확인할 수 μžˆλ„λ‘ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μΆ”κ°€ν•œλ‹€. + +### 7️⃣ κ΅¬λΆ„μžλ₯Ό λ‹¨μˆœ ν•„λ“œ λ³€μˆ˜λ‘œ 관리쀑 β†’ κ΅¬λΆ„μž 관리λ₯Ό μœ„ν•œ 별도 클래슀 생성 + +- [x] `Delimiters` 클래슀λ₯Ό μƒμ„±ν•˜μ—¬, κ΅¬λΆ„μž λͺ©λ‘μ„ κ΄€λ¦¬ν•˜λ„λ‘ μˆ˜μ •ν•œλ‹€. + +### 8️⃣ μ»€μŠ€ν…€ κ΅¬λΆ„μžμ— λŒ€ν•œ 처리λ₯Ό `InputFilter` ν΄λž˜μŠ€μ—μ„œ μ „λ‹΄ν•˜κ³  μžˆλŠ” 상황 β†’ `CustomDelimiterProcessor` 클래슀 생성을 ν†΅ν•œ μ±…μž„ 뢄리 + +- [x] κΈ°μ‘΄ `InputFilter` ν΄λž˜μŠ€μ— 있던 μ»€μŠ€ν…€ κ΅¬λΆ„μž 처리 λ‘œμ§μ„ `CustomDelimiterProcessor` 클래슀둜 μ΄λ™μ‹œν‚¨λ‹€. \ No newline at end of file diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..ddac22af47 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,14 @@ package calculator; +import calculator.config.ApplicationConfig; +import calculator.controller.CalculatorController; + public class Application { - public static void main(String[] args) { - // TODO: ν”„λ‘œκ·Έλž¨ κ΅¬ν˜„ - } + + public static void main(String[] args) { + ApplicationConfig applicationConfig = new ApplicationConfig(); + CalculatorController calculatorController = applicationConfig.initializeController(); + + calculatorController.run(); + } } diff --git a/src/main/java/calculator/config/ApplicationConfig.java b/src/main/java/calculator/config/ApplicationConfig.java new file mode 100644 index 0000000000..b598c1c417 --- /dev/null +++ b/src/main/java/calculator/config/ApplicationConfig.java @@ -0,0 +1,22 @@ +package calculator.config; + +import calculator.controller.CalculatorController; +import calculator.model.Calculator; +import calculator.model.InputFilter; +import calculator.model.delimiter.CustomDelimiterProcessor; +import calculator.model.delimiter.Delimiters; +import calculator.view.InputView; +import calculator.view.OutputView; + +public class ApplicationConfig { + public CalculatorController initializeController() { + return new CalculatorController( + new InputView(), + new OutputView(), + new Delimiters(), + new CustomDelimiterProcessor(), + new InputFilter(), + new Calculator() + ); + } +} diff --git a/src/main/java/calculator/config/CustomDelimiterPattern.java b/src/main/java/calculator/config/CustomDelimiterPattern.java new file mode 100644 index 0000000000..7372cb51fd --- /dev/null +++ b/src/main/java/calculator/config/CustomDelimiterPattern.java @@ -0,0 +1,20 @@ +package calculator.config; + +public enum CustomDelimiterPattern { + START("//"), + END("\\n"); + + private final String pattern; + + CustomDelimiterPattern(String pattern) { + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } + + public int getPatternLength() { + return pattern.length(); + } +} diff --git a/src/main/java/calculator/config/DefaultDelimiter.java b/src/main/java/calculator/config/DefaultDelimiter.java new file mode 100644 index 0000000000..89db69ea98 --- /dev/null +++ b/src/main/java/calculator/config/DefaultDelimiter.java @@ -0,0 +1,16 @@ +package calculator.config; + +public enum DefaultDelimiter { + COMMA(","), + COLON(":"); + + private final String delimiter; + + DefaultDelimiter(String delimiter) { + this.delimiter = delimiter; + } + + public String getDelimiter() { + return delimiter; + } +} diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java new file mode 100644 index 0000000000..0d23b13d89 --- /dev/null +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -0,0 +1,74 @@ +package calculator.controller; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import calculator.model.Calculator; +import calculator.model.delimiter.CustomDelimiterProcessor; +import calculator.model.delimiter.Delimiters; +import calculator.model.InputFilter; +import calculator.view.InputView; +import calculator.view.OutputView; + +public class CalculatorController { + private final InputView inputView; + private final OutputView outputView; + private final Delimiters delimiters; + private final CustomDelimiterProcessor customDelimiterProcessor; + private final InputFilter inputFilter; + private final Calculator calculator; + + public CalculatorController( + InputView inputView, + OutputView outputView, + Delimiters delimiters, + CustomDelimiterProcessor customDelimiterProcessor, + InputFilter inputFilter, + Calculator calculator + ) { + this.inputView = inputView; + this.outputView = outputView; + this.delimiters = delimiters; + this.customDelimiterProcessor = customDelimiterProcessor; + this.inputFilter = inputFilter; + this.calculator = calculator; + } + + public void run() { + String input = readInput(); + + String processedInput = processCustomDelimiter(input); + Set numbers = extractNumbers(processedInput); + int result = sum(numbers); + + printResult(result); + } + + private String readInput() { + outputView.printReadCommand(); + String input = inputView.readInput(); + inputView.closeRead(); + + return input; + } + + private String processCustomDelimiter(String input) { + Optional customDelimiter = customDelimiterProcessor.extractCustomDelimiter(input); + customDelimiter.ifPresent(delimiters::addDelimiter); + + return customDelimiterProcessor.removeCustomDelimiterPattern(input); + } + + private Set extractNumbers(String processedInput) { + return inputFilter.extractNumbers(processedInput, delimiters); + } + + private int sum(Set numbers) { + return calculator.sum(numbers); + } + + private void printResult(int result) { + outputView.printResult(result); + } +} diff --git a/src/main/java/calculator/exception/ErrorMessage.java b/src/main/java/calculator/exception/ErrorMessage.java new file mode 100644 index 0000000000..8ff3369721 --- /dev/null +++ b/src/main/java/calculator/exception/ErrorMessage.java @@ -0,0 +1,30 @@ +package calculator.exception; + +public enum ErrorMessage { + // prefix + ERROR_PREFIX("[ERROR] "), + + // delimiter + INVALID_DELIMITER("ν—ˆμš©λ˜μ§€ μ•Šμ€ κ΅¬λΆ„μžκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€."), + INVALID_CUSTOM_DELIMITER("μ»€μŠ€ν…€ κ΅¬λΆ„μžλŠ” μ •μˆ˜μΌ 수 μ—†μŠ΅λ‹ˆλ‹€."), + EMPTY_CUSTOM_DELIMITER("μ»€μŠ€ν…€ κ΅¬λΆ„μžλŠ” 빈 λ¬Έμžμ—΄μΌ 수 μ—†μŠ΅λ‹ˆλ‹€."), + + // calculator + NON_INTEGER_VALUE("계산기에 μž…λ ₯될 μˆ«μžλŠ” μ •μˆ˜μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€."), + NON_POSITIVE_NUMBER("계산기에 μž…λ ₯될 μˆ«μžλŠ” μ–‘μˆ˜μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€."), + + // custom delimiter pattern + INVALID_START_PATTERN("μ»€μŠ€ν…€ κ΅¬λΆ„μžμ˜ μ‹œμž‘ νŒ¨ν„΄μ΄ μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."), + INVALID_END_PATTERN("μ»€μŠ€ν…€ κ΅¬λΆ„μžμ˜ μ’…λ£Œ νŒ¨ν„΄μ΄ μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."), + INVALID_PATTERN_POSITION("μ»€μŠ€ν…€ κ΅¬λΆ„μžμ˜ μœ„μΉ˜κ°€ μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."); + + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return ERROR_PREFIX.message + message; + } +} diff --git a/src/main/java/calculator/model/Calculator.java b/src/main/java/calculator/model/Calculator.java new file mode 100644 index 0000000000..79c3ef6594 --- /dev/null +++ b/src/main/java/calculator/model/Calculator.java @@ -0,0 +1,11 @@ +package calculator.model; + +import java.util.Set; + +public class Calculator { + public int sum(Set numbers) { + return numbers.stream() + .mapToInt(Integer::intValue) + .sum(); + } +} diff --git a/src/main/java/calculator/model/InputFilter.java b/src/main/java/calculator/model/InputFilter.java new file mode 100644 index 0000000000..9a0818ed04 --- /dev/null +++ b/src/main/java/calculator/model/InputFilter.java @@ -0,0 +1,39 @@ +package calculator.model; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import calculator.model.delimiter.Delimiters; +import calculator.validation.InputValidator; + +public class InputFilter { + public Set extractNumbers(String processedInput, Delimiters delimiters) { + if (processedInput.isBlank()) { + return Set.of(0); + } + String[] splitParts = splitInput(processedInput, delimiters); + validateEachPart(splitParts); + + return mapToIntegerSet(splitParts); + } + + private String[] splitInput(String processedInput, Delimiters delimiters) { + InputValidator.validateInvalidDelimiter(processedInput, delimiters); + String regex = String.join("|", delimiters.getRegex()); + + return processedInput.split(regex); + } + + private static void validateEachPart(String[] splitParts) { + Arrays.stream(splitParts) + .map(String::trim) + .forEach(InputValidator::validateCalculatorNumber); + } + + private static Set mapToIntegerSet(String[] splitParts) { + return Arrays.stream(splitParts) + .map(Integer::valueOf) + .collect(Collectors.toUnmodifiableSet()); + } +} diff --git a/src/main/java/calculator/model/delimiter/CustomDelimiterProcessor.java b/src/main/java/calculator/model/delimiter/CustomDelimiterProcessor.java new file mode 100644 index 0000000000..8aa7812f97 --- /dev/null +++ b/src/main/java/calculator/model/delimiter/CustomDelimiterProcessor.java @@ -0,0 +1,53 @@ +package calculator.model.delimiter; + +import static calculator.config.CustomDelimiterPattern.*; + +import java.util.Optional; + +import calculator.validation.InputValidator; + +public class CustomDelimiterProcessor { + public String removeCustomDelimiterPattern(String input) { + if (hasCustomDelimiterPattern(input)) { + int endIndex = findEndIndex(input); + + return input.substring(endIndex + END.getPatternLength()); + } + + return input; + } + + public Optional extractCustomDelimiter(String input) { + if (!hasCustomDelimiterPattern(input)) { + return Optional.empty(); + } + int startIndex = findStartIndex(input); + int endIndex = findEndIndex(input); + + return Optional.of(extractCustomDelimiter(input, startIndex, endIndex)); + } + + private boolean hasCustomDelimiterPattern(String input) { + return input.contains(START.getPattern()) && input.contains(END.getPattern()); + } + + private int findStartIndex(String input) { + int startIndex = input.indexOf(START.getPattern()); + InputValidator.validateStartPattern(startIndex); + + return startIndex + START.getPatternLength(); + } + + private int findEndIndex(String input) { + int endIndex = input.indexOf(END.getPattern()); + InputValidator.validateEndPattern(endIndex); + + return endIndex; + } + + private String extractCustomDelimiter(String input, int start, int end) { + InputValidator.validatePatternPosition(start, end); + + return input.substring(start, end); + } +} diff --git a/src/main/java/calculator/model/delimiter/Delimiters.java b/src/main/java/calculator/model/delimiter/Delimiters.java new file mode 100644 index 0000000000..f1c549ae0b --- /dev/null +++ b/src/main/java/calculator/model/delimiter/Delimiters.java @@ -0,0 +1,43 @@ +package calculator.model.delimiter; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +import calculator.config.DefaultDelimiter; +import calculator.validation.InputValidator; + +public class Delimiters { + private final Set delimiters = new HashSet<>(); + + public Delimiters() { + initDefaultDelimiters(); + } + + public void addDelimiter(String delimiterInput) { + InputValidator.validateEmpty(delimiterInput); + InputValidator.validateNonDigit(delimiterInput); + delimiters.add(delimiterInput); + } + + public boolean isRegisteredDelimiter(String delimiter) { + return delimiters.contains(delimiter); + } + + public String[] getRegex() { + return delimiters.stream() + .map(Pattern::quote) + .toArray(String[]::new); + } + + private void initDefaultDelimiters() { + Arrays.stream(DefaultDelimiter.values()) + .forEach(delimiter -> this.delimiters.add(delimiter.getDelimiter())); + } + + public Set getDelimiters() { + return Collections.unmodifiableSet(delimiters); + } +} diff --git a/src/main/java/calculator/validation/InputValidator.java b/src/main/java/calculator/validation/InputValidator.java new file mode 100644 index 0000000000..0684b40598 --- /dev/null +++ b/src/main/java/calculator/validation/InputValidator.java @@ -0,0 +1,69 @@ +package calculator.validation; + +import static calculator.exception.ErrorMessage.*; + +import calculator.model.delimiter.Delimiters; + +public class InputValidator { + private InputValidator() { + } + + public static void validateInvalidDelimiter(String input, Delimiters delimiters) { + String regex = "[\\d" + String.join("", delimiters.getRegex()) + "]*"; + + if (!input.matches(regex)) { + throw new IllegalArgumentException(INVALID_DELIMITER.getMessage()); + } + } + + public static void validateNonDigit(String input) { + if (isDigit(input)) { + throw new IllegalArgumentException(INVALID_CUSTOM_DELIMITER.getMessage()); + } + } + + public static void validateCalculatorNumber(String input) { + validateDigit(input); + validateNumberPositive(input); + } + + private static void validateDigit(String input) { + if (!isDigit(input)) { + throw new IllegalArgumentException(NON_INTEGER_VALUE.getMessage()); + } + } + + private static boolean isDigit(String input) { + return input.chars().allMatch(Character::isDigit); + } + + private static void validateNumberPositive(String input) { + if (Integer.parseInt(input) <= 0) { + throw new IllegalArgumentException(NON_POSITIVE_NUMBER.getMessage()); + } + } + + public static void validateEmpty(String input) { + if (input.isEmpty()) { + throw new IllegalArgumentException(EMPTY_CUSTOM_DELIMITER.getMessage()); + } + } + + public static void validateStartPattern(int startIndex) { + if (startIndex == -1) { + throw new IllegalArgumentException(INVALID_START_PATTERN.getMessage()); + } + } + + public static void validateEndPattern(int endIndex) { + if (endIndex == -1) { + throw new IllegalArgumentException(INVALID_END_PATTERN.getMessage()); + } + } + + public static void validatePatternPosition(int start, int end) { + if (start >= end) { + throw new IllegalArgumentException(INVALID_PATTERN_POSITION.getMessage()); + } + } +} diff --git a/src/main/java/calculator/view/InputView.java b/src/main/java/calculator/view/InputView.java new file mode 100644 index 0000000000..497cdd9986 --- /dev/null +++ b/src/main/java/calculator/view/InputView.java @@ -0,0 +1,13 @@ +package calculator.view; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + public String readInput() { + return Console.readLine(); + } + + public void closeRead() { + Console.close(); + } +} diff --git a/src/main/java/calculator/view/OutputView.java b/src/main/java/calculator/view/OutputView.java new file mode 100644 index 0000000000..90eebed053 --- /dev/null +++ b/src/main/java/calculator/view/OutputView.java @@ -0,0 +1,13 @@ +package calculator.view; + +import static calculator.view.PrintMessage.*; + +public class OutputView { + public void printReadCommand() { + System.out.println(READ_COMMAND.getMessage()); + } + + public void printResult(int result) { + System.out.printf((RESULT.getMessage()), result); + } +} diff --git a/src/main/java/calculator/view/PrintMessage.java b/src/main/java/calculator/view/PrintMessage.java new file mode 100644 index 0000000000..46fc82ec10 --- /dev/null +++ b/src/main/java/calculator/view/PrintMessage.java @@ -0,0 +1,16 @@ +package calculator.view; + +public enum PrintMessage { + READ_COMMAND("λ§μ…ˆν•  λ¬Έμžμ—΄μ„ μž…λ ₯ν•΄ μ£Όμ„Έμš”."), + RESULT("κ²°κ³Ό : %d"); + + private final String message; + + PrintMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +}