diff --git a/README.md b/README.md index bd90ef0247..83879be7ca 100644 --- a/README.md +++ b/README.md @@ -1 +1,24 @@ -# java-calculator-precourse \ No newline at end of file +# java-calculator-precourse + +--- + +## ๐Ÿ› ๏ธ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก + +### ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฌธ์ž์—ด ์ฝ๋Š” ๊ธฐ๋Šฅ + +- [x] camp.nextstep.edu.missionutils์—์„œ ์ œ๊ณตํ•˜๋Š” Console API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ + +### ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž ์ถ”์ถœ ๊ธฐ๋Šฅ + +- [x] ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๊ฐ€ ์žˆ์„์‹œ, ๊ตฌ๋ถ„์ž List์— ์ถ”๊ฐ€ +- [x] ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๋Š” 1๊ฐœ๋กœ ์ œํ•œ (์ถ”ํ›„์— ๋ฆฌํŒฉํ† ๋ง ์˜ˆ์ •) +- [x] ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๋กœ ์ˆซ์ž๋Š” ๋ถˆ๊ฐ€๋Šฅ + +### ์ˆซ์ž ์ถ”์ถœ ๊ธฐ๋Šฅ + +- [x] StringBuilder์™€ ์ •๊ทœ ํ‘œํ˜„์‹์„ ์ด์šฉํ•˜์—ฌ ์ˆซ์ž๋งŒ ์ถ”์ถœ +- [x] ์Œ์ˆ˜ ํฌํ•จ ์‹œ ์—๋Ÿฌ ๋ฐœ์ƒ + +### ๊ณ„์‚ฐ ๊ธฐ๋Šฅ + +- [x] ์ถ”์ถœํ•œ ์ˆซ์ž ๋ฐ”ํƒ•์œผ๋กœ ๋ง์…ˆ ์—ฐ์‚ฐ diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..eebda43305 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,13 @@ package calculator; +import calculator.controller.CalculatorController; + public class Application { + public static void main(String[] args) { // TODO: ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„ + CalculatorController calculatorController = new CalculatorController(); + calculatorController.run(); } + } diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java new file mode 100644 index 0000000000..d8103a2375 --- /dev/null +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -0,0 +1,35 @@ +package calculator.controller; + +import calculator.model.Calculator; +import calculator.model.Extractor; +import calculator.view.InputView; +import calculator.view.OutputView; +import java.util.List; + +public class CalculatorController { + + private final Calculator calculator; + private final Extractor extractor; + private final InputView inputView; + private final OutputView outputView; + + public CalculatorController() { + this.calculator = new Calculator(); + this.extractor = new Extractor(); + this.inputView = new InputView(); + this.outputView = new OutputView(); + } + + public void run() { + + String input = inputView.read(); + inputView.close(); + + extractor.extractCustomDelimiter(input); + List numbers = extractor.extractNumbers(input); + + long result = calculator.calculateSum(numbers); + + outputView.print(result); + } +} diff --git a/src/main/java/calculator/global/CustomDelimiterIndex.java b/src/main/java/calculator/global/CustomDelimiterIndex.java new file mode 100644 index 0000000000..7486f5e40d --- /dev/null +++ b/src/main/java/calculator/global/CustomDelimiterIndex.java @@ -0,0 +1,18 @@ +package calculator.global; + +public enum CustomDelimiterIndex { + + CUSTOM_DELIMITER_INDEX(2), //์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž ์ธ๋ฑ์Šค + CUSTOM_DELIMITER_SUFFIX_START(3), // \n ์‹œ์ž‘ ์ธ๋ฑ์Šค + CUSTOM_DELIMITER_SUFFIX_END(4); // \n ๋ ์ธ๋ฑ์Šค + + private final int key; + + CustomDelimiterIndex(int key) { + this.key = key; + } + + public int getKey() { + return key; + } +} diff --git a/src/main/java/calculator/global/DefaultDelimiter.java b/src/main/java/calculator/global/DefaultDelimiter.java new file mode 100644 index 0000000000..a4080d5d82 --- /dev/null +++ b/src/main/java/calculator/global/DefaultDelimiter.java @@ -0,0 +1,17 @@ +package calculator.global; + +public enum DefaultDelimiter { + + COMMA(','), + COLON(':'); + + private final char key; + + DefaultDelimiter(char key) { + this.key = key; + } + + public char getKey() { + return key; + } +} diff --git a/src/main/java/calculator/global/DelimiterMarker.java b/src/main/java/calculator/global/DelimiterMarker.java new file mode 100644 index 0000000000..56c28d7243 --- /dev/null +++ b/src/main/java/calculator/global/DelimiterMarker.java @@ -0,0 +1,17 @@ +package calculator.global; + +public enum DelimiterMarker { + + PREFIX("//"), // ์ปค์Šคํ…€ ์ƒ์„ฑ์ž ์•ž๋ถ€๋ถ„ + SUFFIX("\\n"); // ์ปค์Šคํ…€ ์ƒ์„ฑ์ž ๋’ท๋ถ€๋ถ„ + + private final String key; + + DelimiterMarker(String key) { + this.key = key; + } + + public String getKey() { + return key; + } +} diff --git a/src/main/java/calculator/global/MakeRegexDelimiter.java b/src/main/java/calculator/global/MakeRegexDelimiter.java new file mode 100644 index 0000000000..1e3fda25ce --- /dev/null +++ b/src/main/java/calculator/global/MakeRegexDelimiter.java @@ -0,0 +1,19 @@ +package calculator.global; + +public enum MakeRegexDelimiter { + + START("//"), // ์‹œ์ž‘ ๊ตฌ๋ถ„์ž + OPEN_BRACKET("["), // ์—ฌ๋Š” ๋Œ€๊ด„ํ˜ธ + CLOSE_BRACKET("]"); // ๋‹ซ๋Š” ๋Œ€๊ด„ํ˜ธ + + private final String key; + + MakeRegexDelimiter(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + +} diff --git a/src/main/java/calculator/model/Calculator.java b/src/main/java/calculator/model/Calculator.java new file mode 100644 index 0000000000..6b7b93ab4d --- /dev/null +++ b/src/main/java/calculator/model/Calculator.java @@ -0,0 +1,18 @@ +package calculator.model; + +import java.util.List; + +public class Calculator { + + /** + * @param numbers ๊ณ„์‚ฐํ•  Long ํƒ€์ž… List + * @return ๊ณ„์‚ฐ๋œ ํ•ฉ + */ + public long calculateSum(List numbers) { + long sum = 0; + for (Long number : numbers) { + sum += number; + } + return sum; + } +} diff --git a/src/main/java/calculator/model/Extractor.java b/src/main/java/calculator/model/Extractor.java new file mode 100644 index 0000000000..441829596a --- /dev/null +++ b/src/main/java/calculator/model/Extractor.java @@ -0,0 +1,106 @@ +package calculator.model; + +import calculator.global.CustomDelimiterIndex; +import calculator.global.DefaultDelimiter; +import calculator.global.DelimiterMarker; +import calculator.global.MakeRegexDelimiter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Extractor { + + private final List delimiters = new ArrayList<>( + Arrays.asList(DefaultDelimiter.COMMA.getKey(), DefaultDelimiter.COLON.getKey())); + private boolean hasCustomDelimiter = false; + + /** + * @param input ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๋ฅผ ์ถ”์ถœํ•  ๋ฌธ์ž์—ด ์กฐ๊ฑด์— ๋งž๋Š” ์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๋ฅผ ์ถ”์ถœํ•˜์—ฌ delimiters ํ•„๋“œ์— ์ถ”๊ฐ€ hasCustomDelimiter ํ•„๋“œ๋ฅผ true ๋ณ€๊ฒฝ + */ + public void extractCustomDelimiter(String input) { + + if (input.startsWith(DelimiterMarker.PREFIX.getKey()) && + input.substring(CustomDelimiterIndex.CUSTOM_DELIMITER_SUFFIX_START.getKey(), + CustomDelimiterIndex.CUSTOM_DELIMITER_SUFFIX_END.getKey() + 1) + .equals(DelimiterMarker.SUFFIX.getKey()) + ) { + + char delimiter = input.charAt(CustomDelimiterIndex.CUSTOM_DELIMITER_INDEX.getKey()); + + isNumber(delimiter); + + delimiters.add(delimiter); + hasCustomDelimiter = true; + } + } + + /** + * @param input ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•  ๋ฌธ์ž์—ด + * @return ์ถ”์ถœ๋œ ์ˆซ์ž์˜ List + */ + + public List extractNumbers(String input) { + + List numbers = new ArrayList<>(); + + input = removeCustomDelimiter(input); + + String regex = makeRegex(); + + // ๊ตฌ๋ถ„์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์ž์—ด์„ ์ˆซ์ž๋“ค๋กœ ๋ถ„๋ฆฌ + // ์ด๋•Œ ๊ตฌ๋ถ„์ž๊ฐ€ ์•„๋‹Œ ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ˆซ์ž์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ์—์„œ ๊ฑธ๋Ÿฌ์ง + String[] tokens = input.split(regex); + for (String token : tokens) { + if (!token.isEmpty()) { + Long number = validateIsNumber(token); + validateNegativeNumber(number); + numbers.add(number); + } + } + + return numbers; + } + + //์ˆซ์ž์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private void isNumber(char input) { + if (Character.isDigit(input)) { + throw new IllegalArgumentException("์ˆซ์ž์ธ ๊ตฌ๋ถ„์ž๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + //์ปค์Šคํ…€ ๊ตฌ๋ถ„์ž๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private String removeCustomDelimiter(String input) { + if (hasCustomDelimiter) { + input = input.substring(CustomDelimiterIndex.CUSTOM_DELIMITER_SUFFIX_END.getKey() + 1); + } + return input; + } + + //๊ตฌ๋ถ„์ž๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private String makeRegex() { + StringBuilder regex = new StringBuilder(MakeRegexDelimiter.OPEN_BRACKET.getKey()); + for (char delimiter : delimiters) { + regex.append(MakeRegexDelimiter.START.getKey()).append(delimiter); + } + regex.append(MakeRegexDelimiter.CLOSE_BRACKET.getKey()); + + return regex.toString(); + } + + //๋ถ„๋ฆฌํ•œ ๋ฌธ์ž์—ด์ด ์ˆซ์ž์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private Long validateIsNumber(String input) { + try { + return Long.parseLong(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("์ž˜๋ชป๋œ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค."); + } + } + + //์Œ์ˆ˜์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private void validateNegativeNumber(Long number) { + if (number < 0) { + throw new IllegalArgumentException("์Œ์ˆ˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค."); + } + } + +} diff --git a/src/main/java/calculator/view/InputView.java b/src/main/java/calculator/view/InputView.java new file mode 100644 index 0000000000..271c76bfc1 --- /dev/null +++ b/src/main/java/calculator/view/InputView.java @@ -0,0 +1,23 @@ +package calculator.view; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + + /** + * ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ + * + * @return ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ + */ + public String read() { + System.out.println("๋ง์…ˆํ•  ๋ฌธ์ž์—ด์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + return Console.readLine(); + } + + /** + * ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›๊ณ , Console์„ ๋‹ซ๋Š” ๋ฉ”์†Œ๋“œ + */ + public void close() { + 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..cbf066e621 --- /dev/null +++ b/src/main/java/calculator/view/OutputView.java @@ -0,0 +1,11 @@ +package calculator.view; + +public class OutputView { + + /** + * @param result ์ถœ๋ ฅํ•  ๊ฒฐ๊ณผ๊ฐ’ + */ + public void print(long result) { + System.out.println("๊ฒฐ๊ณผ : " + result); + } +}