diff --git a/README.md b/README.md index bd90ef0247..adba965cd3 100644 --- a/README.md +++ b/README.md @@ -1 +1,36 @@ -# java-calculator-precourse \ No newline at end of file +# java-calculator-precourse +___ + +## InputHandler +> 입력을 처리하는 클래스 +### Reader +> 입력을 수행하는 클래스 + + +## OuputHandler +> 출력을 처리하는 클래스 +### Printer +> 출력을 수행하는 클래스 + + +## NumberHandler +> 숫자를 관리하는 클래스 +### Number +> 숫자를 구체화 한 클래스 + + +## DelimiterHandler +> 구분자를 관리하는 클래스 +### Delimiter +> 구분자를 구체화 한 클래스 + +## UserInputParser +> 사용자 입력을 파싱하는 클래스 + +## ServiceHandler +> 도메인 흐름을 담당하는 클래스 + +## Controller +> 입출력을 담당하고 ServiceHandler에게 도메인 로직을 요청하는 클래스 + + diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..1523c0cba8 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,11 @@ package calculator; +import calculator.controller.Controller; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + Controller controller = new Controller(); + + controller.run(); } } diff --git a/src/main/java/calculator/controller/Controller.java b/src/main/java/calculator/controller/Controller.java new file mode 100644 index 0000000000..d4c27235d8 --- /dev/null +++ b/src/main/java/calculator/controller/Controller.java @@ -0,0 +1,15 @@ +package calculator.controller; + +import calculator.io.InputHandler; +import calculator.io.OutputHandler; +import calculator.service.domain.ServiceHandler; + +public class Controller { + private final ServiceHandler serviceHandler = new ServiceHandler(); + + public void run() { + String userInupt = InputHandler.makeDelimiterNumberString(); + String answer = serviceHandler.calculate(userInupt); + OutputHandler.printResult(answer); + } +} diff --git a/src/main/java/calculator/io/InputHandler.java b/src/main/java/calculator/io/InputHandler.java new file mode 100644 index 0000000000..564cc75a7b --- /dev/null +++ b/src/main/java/calculator/io/InputHandler.java @@ -0,0 +1,10 @@ +package calculator.io; + +public class InputHandler { + public static String makeDelimiterNumberString() { + Printer.printMessage("덧셈할 문자열을 입력해 주세요."); + Printer.printNewLine(); + + return Reader.getString(); + } +} diff --git a/src/main/java/calculator/io/OutputHandler.java b/src/main/java/calculator/io/OutputHandler.java new file mode 100644 index 0000000000..b24d949717 --- /dev/null +++ b/src/main/java/calculator/io/OutputHandler.java @@ -0,0 +1,11 @@ +package calculator.io; + +public class OutputHandler { + public static void printResult(String result) { + Printer.printMessageWithFormat("결과 : %s", makeResultLikeInteger(result)); + } + + private static String makeResultLikeInteger(String result) { + return result.replaceAll("\\.0$", ""); + } +} diff --git a/src/main/java/calculator/io/Printer.java b/src/main/java/calculator/io/Printer.java new file mode 100644 index 0000000000..a8df6f4ca7 --- /dev/null +++ b/src/main/java/calculator/io/Printer.java @@ -0,0 +1,15 @@ +package calculator.io; + +public class Printer { + public static void printMessage(String message) { + System.out.printf(message); + } + + public static void printMessageWithFormat(String format, Object... args) { + System.out.printf(format, args); + } + + public static void printNewLine() { + System.out.println(); + } +} diff --git a/src/main/java/calculator/io/Reader.java b/src/main/java/calculator/io/Reader.java new file mode 100644 index 0000000000..c39b7bfbed --- /dev/null +++ b/src/main/java/calculator/io/Reader.java @@ -0,0 +1,9 @@ +package calculator.io; + +import camp.nextstep.edu.missionutils.Console; + +public class Reader { + public static String getString() { + return Console.readLine(); + } +} diff --git a/src/main/java/calculator/service/domain/Delimiter.java b/src/main/java/calculator/service/domain/Delimiter.java new file mode 100644 index 0000000000..55896d4d0f --- /dev/null +++ b/src/main/java/calculator/service/domain/Delimiter.java @@ -0,0 +1,42 @@ +package calculator.service.domain; + +public class Delimiter { + private final char delimiter; + + public Delimiter(char delimiter) { + this.delimiter = delimiter; + } + + /** + * 두 객체가 값이 동일한지 비교하도록 재정의. + * + * @param obj 비교 대상 객체 + * @return 값이 동일하다면 true, 동일하지 않다면 false + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; // 같은 객체라면 값을 비교할 이유가 없기 때문에 바로 true를 반환하여 성능을 최적화한다. + } + if (obj == null || getClass() != obj.getClass()) { + return false; // Null Handling, Class Consistency + } + Delimiter other = (Delimiter) obj; // 다운캐스팅 + return this.delimiter == other.delimiter; // 값 비교 + } + + public boolean hasSameValueAs(Delimiter other) { + if (this == other) { + return true; // 객체 동등성 체크 + } + if (other == null) { + return false; // Null Handling + } + return this.delimiter == other.delimiter; // 값 비교 + } + + @Override + public int hashCode() { + return Character.hashCode(delimiter); + } +} diff --git a/src/main/java/calculator/service/domain/DelimiterHandler.java b/src/main/java/calculator/service/domain/DelimiterHandler.java new file mode 100644 index 0000000000..5917bbf8d3 --- /dev/null +++ b/src/main/java/calculator/service/domain/DelimiterHandler.java @@ -0,0 +1,37 @@ +package calculator.service.domain; + +import java.util.ArrayList; +import java.util.List; + +public class DelimiterHandler { + private final List delimiterList; + + public DelimiterHandler() { + delimiterList = new ArrayList<>(List.of(new Delimiter(','), new Delimiter(':'))); + } + + public void addDelimiter(char delimiter) { + if (!checkDuplicate(new Delimiter(delimiter))) { + delimiterList.add(new Delimiter(delimiter)); + } + } + + public boolean isValidDelimiter(char delimiter) { + Delimiter target = new Delimiter(delimiter); + for (Delimiter each : delimiterList) { + if (each.equals(target)) { + return true; + } + } + return false; + } + + private boolean checkDuplicate(Delimiter newDelimiter) { + for (Delimiter each : delimiterList) { + if (each.hasSameValueAs(newDelimiter)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/calculator/service/domain/Number.java b/src/main/java/calculator/service/domain/Number.java new file mode 100644 index 0000000000..87027a301e --- /dev/null +++ b/src/main/java/calculator/service/domain/Number.java @@ -0,0 +1,21 @@ +package calculator.service.domain; + +import java.util.Arrays; +import java.util.Objects; + +public class Number { + private final double numberValue; + + public Number(double numberValue) { + this.numberValue = numberValue; + } + + public Number add(Number other) { + return new Number(this.numberValue + other.numberValue); + } + + @Override + public String toString() { + return String.valueOf(numberValue); + } +} diff --git a/src/main/java/calculator/service/domain/NumberHandler.java b/src/main/java/calculator/service/domain/NumberHandler.java new file mode 100644 index 0000000000..f501b39a76 --- /dev/null +++ b/src/main/java/calculator/service/domain/NumberHandler.java @@ -0,0 +1,28 @@ +package calculator.service.domain; + +import java.util.ArrayList; +import java.util.List; + +public class NumberHandler { + private final List numberList; + + public NumberHandler() { + numberList = new ArrayList<>(); + } + + public void addNumber(Double number) { + if (number < 0) { + throw new IllegalArgumentException("음수는 입력할 수 없습니다."); + } + numberList.add(new Number(number)); + } + + public String calculatePlus() { + Number answer = new Number(0); + for (Number each : numberList) { + answer = answer.add(each); + } + + return answer.toString(); + } +} diff --git a/src/main/java/calculator/service/domain/ServiceHandler.java b/src/main/java/calculator/service/domain/ServiceHandler.java new file mode 100644 index 0000000000..38e761d778 --- /dev/null +++ b/src/main/java/calculator/service/domain/ServiceHandler.java @@ -0,0 +1,28 @@ +package calculator.service.domain; + +import java.util.List; + +public class ServiceHandler { + private final NumberHandler numberHandler = new NumberHandler(); + private final DelimiterHandler delimiterHandler = new DelimiterHandler(); + + public String calculate(String userInput) { + setDelimiterHandler(userInput); + setNumberHandler(userInput, delimiterHandler); + return numberHandler.calculatePlus(); + } + + private void setNumberHandler(String userInput, DelimiterHandler delimiterHandler) { + List numbers = UserInputParser.parseNumber(userInput, delimiterHandler); + for (Double each : numbers) { + numberHandler.addNumber(each); + } + } + + private void setDelimiterHandler(String userInput) { + List customDelimiter = UserInputParser.parseCustomDelimiter(userInput); + for (Character each : customDelimiter) { + delimiterHandler.addDelimiter(each); + } + } +} diff --git a/src/main/java/calculator/service/domain/UserInputParser.java b/src/main/java/calculator/service/domain/UserInputParser.java new file mode 100644 index 0000000000..523aa11c25 --- /dev/null +++ b/src/main/java/calculator/service/domain/UserInputParser.java @@ -0,0 +1,84 @@ +package calculator.service.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UserInputParser { + private static final int DELIMITER_INDEX = 2; + + public static List parseCustomDelimiter(String userInput) { + List result = extractChars(userInput); + + return result; + } + + public static List parseNumber(String userInput, DelimiterHandler delimiterHandler) { + String userInputAfterParse = getUserInputAfterParse(userInput); + checkOnlyNumberAndDelimiter(userInputAfterParse, delimiterHandler); + List result = extractNumbers(userInputAfterParse, delimiterHandler); + + return result; + } + + private static void checkOnlyNumberAndDelimiter(String userInputAfterParse, DelimiterHandler delimiterHandler) { + for (Character each : userInputAfterParse.toCharArray()) { + if (!Character.isDigit(each) && !delimiterHandler.isValidDelimiter(each)) { + throw new IllegalArgumentException("형식에 맞지 않는 문자열을 입력했습니다."); + } + } + } + + private static List extractNumbers(String userInputAfterParse, DelimiterHandler delimiterHandler) { + StringBuilder numberBuilder = new StringBuilder(); + List numberList = new ArrayList<>(); + + for (Character each : userInputAfterParse.toCharArray()) { + if (delimiterHandler.isValidDelimiter(each)) { + if (numberBuilder.isEmpty()) { + continue; + } + numberList.add(Double.valueOf(numberBuilder.toString())); + numberBuilder.delete(0, numberBuilder.length()); + continue; + } + numberBuilder.append(each); + } + + if (!numberBuilder.isEmpty()) { + numberList.add(Double.valueOf(numberBuilder.toString())); + } + return numberList; + } + + private static String getUserInputAfterParse(String userInput) { + String userInputAfterParse = removePatterns(userInput); + + return userInputAfterParse; + } + + private static String removePatterns(String userInput) { + Matcher matcher = createMatcher(userInput); + + return matcher.replaceAll(""); + } + + private static List extractChars(String userInput) { + List result = new ArrayList<>(); + Matcher matcher = createMatcher(userInput); + + while (matcher.find()) { + result.add(matcher.group().charAt(DELIMITER_INDEX)); + } + + return result; + } + + private static Matcher createMatcher(String userInput) { + Pattern pattern = Pattern.compile("//.\\\\n"); + + return pattern.matcher(userInput); + } + +}