Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[계산기] 공희상 제출합니다. #2

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b1fbe2e
feat(message): View에 사용할 문자열 상수 관리 클래스 ViewMessages 추가
023-dev Nov 19, 2024
420cde7
feat(view): 출력을 관리할 OutputView 클래스 추가
023-dev Nov 19, 2024
0b8e3bd
feat(view): 입력을 관리할 InputView 클래스 추가
023-dev Nov 19, 2024
2d45746
feat(controller): 계산기 로직들을 통합해서 관리할 CalculatorController 클래스 추가
023-dev Nov 19, 2024
c7001a7
feat(config): 의존성 주입을 외부에서 책임지는 CalculatorConfig 클래스 추가
023-dev Nov 19, 2024
4a4da6e
feat(controller): 입력에 대한 input 메서드 추가
023-dev Nov 19, 2024
333f918
feat(main): 시작점 main 메서드에 config 및 controller 초기화 로직 추가
023-dev Nov 19, 2024
3443d1f
fix(config): Calculator 생성 로직 new 생성자로 수정
023-dev Nov 19, 2024
7151248
feat(constant): 상수 값 관리를 위한 클래스 Constants 추가
023-dev Nov 19, 2024
574045b
feat(controller): 전반적인 계산기 로직 추가
023-dev Nov 19, 2024
ea2df5a
feat(service): 실질적인 계산 로직을 담은 CalculatorService 클래스 추가
023-dev Nov 19, 2024
a344d41
feat(parser): 숫자 파싱을 위한 클래스 NumberParser 추가
023-dev Nov 19, 2024
c11dd88
feat(validator): Validator 인터페이스 추가
023-dev Nov 19, 2024
297d67d
feat(validator): 구분자 검증을 위한 Validator 인터페이스 구현 클래스 DelimiterValidator 추가
023-dev Nov 19, 2024
70b5286
feat(validator): 숫자 검증을 위한 Validator 인터페이스 구현 클래스 DelimiterValidator 추가
023-dev Nov 19, 2024
d367380
feat(constant): 구분자 로직에 대한 상수 값 추가
023-dev Nov 19, 2024
af2c351
feat(message): 에러 메시지에 대한 문자열 상수 처리 클래스 ErrorMessages 추가
023-dev Nov 19, 2024
9e4cc54
feat(service): 구분자 처리 메서드 parse 추가
023-dev Nov 19, 2024
65cc7b7
feat(config): 서비스에 대한 의존성 주입 로직 추가
023-dev Nov 19, 2024
f231bbb
refactor(main): 시작점 main 메서드에서 초기화 로직 간소화 추가
023-dev Nov 19, 2024
c5b08b8
fix(validator): INVALID_EMPTY 상수 오타 수정
023-dev Nov 19, 2024
1f0dfb0
feat(validator): 입력 검증을 위한 Validator 인터페이스 구현 클래스 InputValidator 추가
023-dev Nov 19, 2024
ac0f2c8
fix(parser): defaultTokens 메서드에서 재귀 메서드명 수정
023-dev Nov 19, 2024
e23adfc
feat(constant): 입력에 대한 패턴 상수 값 추가
023-dev Nov 19, 2024
d6f833c
feat(message): 에러 메시지에 대한 문자열 상수 처리 클래스 ErrorMessages 추가
023-dev Nov 19, 2024
be02c04
feat(controller): 로직 구현
023-dev Nov 19, 2024
c4f0fed
feat: 빈값 입력 처리
023-dev Nov 19, 2024
6e94edc
feat: 빈값 입력 처리
023-dev Nov 19, 2024
aad7fd9
feat: 빈값 입력 처리
023-dev Nov 19, 2024
51ea5cb
feat: 빈값 입력 처리
023-dev Nov 19, 2024
458e59f
test: 기본적인 test코드 추가
023-dev Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/main/java/calculator/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package calculator;

import calculator.config.CalculatorConfig;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
CalculatorConfig calculatorConfig = new CalculatorConfig();
calculatorConfig.run();
}
}
14 changes: 14 additions & 0 deletions src/main/java/calculator/common/constant/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package calculator.common.constant;

public class Constants {

public static final String EMPTY = "";
public static final String COMMA = ",";
public static final String COLON = ":";
public static final String PIPE = "|";
public static final String ZERO = "0";
public static final String DEFAULT_DELIMITERS = String.join(PIPE, COMMA, COLON);
public static final String DEFAULT_DELIMITER_PATTERN = "^[0-9]+([,|:][0-9]+)*$";
public static final String CUSTOM_DELIMITER_PATTERN = "^//.*\\\\n(.*)?$";
public static final String CUSTOM_DELIMITER_PARSE_PATTERN = "//(.*)\\\\n(.*)";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package calculator.common.constant.message;

public class ErrorMessages {
public final static String INVALID_EMPTY = "입력 값은 비어 있을 수 없습니다.";
public final static String INVALID_INPUT_NULL = "입력 값이 유효하지 않습니다.";
public final static String INVALID_INPUT_FORMAT = "입력 문자열이 유효한 형식이 아닙니다.";
public final static String INVALID_CONTAIN_NUMBER = "입력 값에 숫자가 포함될 수 없습니다.";
public final static String INVALID_NUMBER = "유효하지 않은 숫자입니다.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package calculator.common.constant.message;

public class ViewMessages {
public static final String INPUT_PROMPT_MESSAGE = "덧셈할 문자열을 입력해주요.";
public static final String CALCULATOR_RESULT_MESSAGE = "결과 : %d";
}
30 changes: 30 additions & 0 deletions src/main/java/calculator/config/CalculatorConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package calculator.config;

import calculator.controller.CalculatorController;
import calculator.service.CalculatorService;
import calculator.util.parser.NumberParser;
import calculator.util.validator.DelimiterValidator;
import calculator.util.validator.InputValidator;
import calculator.util.validator.NumberValidator;
import calculator.view.InputView;
import calculator.view.OutputView;

public class CalculatorConfig {

private final CalculatorController calculatorController;

public CalculatorConfig() {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
InputValidator inputValidator = new InputValidator();
DelimiterValidator delimiterValidator = new DelimiterValidator();
NumberValidator numberValidator = new NumberValidator();
NumberParser numberParser = new NumberParser(delimiterValidator, numberValidator);
CalculatorService calculatorService = new CalculatorService(inputValidator, numberParser);
this.calculatorController = new CalculatorController(inputView, outputView, calculatorService);
}

public void run() {
calculatorController.run();
}
}
37 changes: 37 additions & 0 deletions src/main/java/calculator/controller/CalculatorController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package calculator.controller;

import calculator.service.CalculatorService;
import calculator.view.InputView;
import calculator.view.OutputView;

public class CalculatorController {

private final InputView inputView;
private final OutputView outputView;
private final CalculatorService calculatorService;

public CalculatorController(InputView inputView, OutputView outputView, CalculatorService calculatorService) {
this.inputView = inputView;
this.outputView = outputView;
this.calculatorService = calculatorService;
}

public void run() {
String input = input();
int result = calculate(input);
result(result);
}

public String input() {
outputView.printInputPrompt();
return inputView.getInput();
}

private int calculate(String input) {
return calculatorService.calculator(input);
}

private void result(int result) {
outputView.printResult(result);
}
}
36 changes: 36 additions & 0 deletions src/main/java/calculator/service/CalculatorService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package calculator.service;

import calculator.util.parser.NumberParser;
import calculator.util.validator.InputValidator;
import java.util.List;

public class CalculatorService {
private final InputValidator inputValidator;
private final NumberParser numberParser;

public CalculatorService(InputValidator inputValidator, NumberParser numberParser) {
this.inputValidator = inputValidator;
this.numberParser = numberParser;
}

public int calculator(String input) {
if (input.isEmpty()) {
return 0;
}
validate(input);
List<Integer> numbers = parse(input);
return sum(numbers);
}

private void validate(String input) {
inputValidator.validate(input);
}

private List<Integer> parse(String input) {
return numberParser.parse(input);
}

private int sum(List<Integer> numbers) {
return numbers.stream().mapToInt(Integer::intValue).sum();
}
}
88 changes: 88 additions & 0 deletions src/main/java/calculator/util/parser/NumberParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package calculator.util.parser;

import static calculator.common.constant.Constants.CUSTOM_DELIMITER_PARSE_PATTERN;
import static calculator.common.constant.Constants.DEFAULT_DELIMITERS;
import static calculator.common.constant.Constants.EMPTY;
import static calculator.common.constant.Constants.PIPE;
import static calculator.common.constant.Constants.ZERO;
import static calculator.common.constant.message.ErrorMessages.INVALID_INPUT_FORMAT;

import calculator.util.validator.DelimiterValidator;
import calculator.util.validator.NumberValidator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;

public class NumberParser {
private final DelimiterValidator delimiterValidator;
private final NumberValidator numberValidator;

private static String delimiters = DEFAULT_DELIMITERS;

public NumberParser(DelimiterValidator delimiterValidator, NumberValidator numberValidator) {
this.delimiterValidator = delimiterValidator;
this.numberValidator = numberValidator;
}

public List<Integer> parse(String input) {
if(input.isEmpty()) {
return List.of(0);
}
List<String> tokens = splitTokens(input);
return toNumbers(tokens);
}

private List<String> splitTokens(String input) {
if (hasCustomDelimiter(input)) {
return customTokens(input);
}
return defaultTokens(input);
}

private boolean hasCustomDelimiter(String input) {
return input.startsWith("//");
}

private List<String> customTokens(String input) {
Matcher matcher = Pattern.compile(CUSTOM_DELIMITER_PARSE_PATTERN).matcher(input);
if (!matcher.find()) {
throw new IllegalArgumentException(INVALID_INPUT_FORMAT);
}
addDelimiter(matcher.group(1));
String numbers = matcher.group(2);
if(numbers == null || numbers.isEmpty()) {
return List.of(ZERO);
}
return splitByDelimiter(matcher.group(2));
}

private void addDelimiter(String customDelimiter) {
for (String delimiter : customDelimiter.split(EMPTY)) {
delimiterValidator.validate(delimiter);
delimiters = String.join(PIPE, delimiters, Pattern.quote(delimiter));
}
}

private List<String> defaultTokens(String input) {
return splitByDelimiter(input);
}

private List<String> splitByDelimiter(String input) {
List<String> tokens = new ArrayList<>();
for (String token : input.split(delimiters)) {
tokens.add(token);
}
return tokens;
}

private List<Integer> toNumbers(List<String> tokens) {
List<Integer> numbers = new ArrayList<>();
for (String token : tokens) {
numberValidator.validate(token);
numbers.add(Integer.parseInt(token));
}
return numbers;
}
}

16 changes: 16 additions & 0 deletions src/main/java/calculator/util/validator/DelimiterValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package calculator.util.validator;

import static calculator.common.constant.message.ErrorMessages.INVALID_CONTAIN_NUMBER;
import static calculator.common.constant.message.ErrorMessages.INVALID_EMPTY;

public class DelimiterValidator implements ValidatorStrategy<String> {
@Override
public void validate(String value) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(INVALID_EMPTY);
}
if (value.matches(".*\\d.*")) {
throw new IllegalArgumentException(INVALID_CONTAIN_NUMBER);
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/calculator/util/validator/InputValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package calculator.util.validator;

import static calculator.common.constant.Constants.CUSTOM_DELIMITER_PATTERN;
import static calculator.common.constant.Constants.DEFAULT_DELIMITER_PATTERN;
import static calculator.common.constant.message.ErrorMessages.INVALID_INPUT_FORMAT;

import java.util.regex.Pattern;

public class InputValidator implements ValidatorStrategy<String> {

@Override
public void validate(String input) {
if (input == null) {
return;
}
if (!isValidInput(input)) {
throw new IllegalArgumentException(INVALID_INPUT_FORMAT);
}
}

private boolean isValidInput(String input) {
return isDefaultDelimiter(input) || isCustomDelimiter(input);
}

private boolean isDefaultDelimiter(String input) {
return Pattern.matches(DEFAULT_DELIMITER_PATTERN, input);
}

private boolean isCustomDelimiter(String input) {
return Pattern.matches(CUSTOM_DELIMITER_PATTERN, input);
}
}
16 changes: 16 additions & 0 deletions src/main/java/calculator/util/validator/NumberValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package calculator.util.validator;

import static calculator.common.constant.message.ErrorMessages.INVALID_NUMBER;

public class NumberValidator implements ValidatorStrategy<String> {
@Override
public void validate(String value) {
try {
if (Integer.parseInt(value) < 0) {
throw new NumberFormatException(INVALID_NUMBER);
}
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(INVALID_NUMBER);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package calculator.util.validator;

public interface ValidatorStrategy <T>{
void validate(T value);
}
11 changes: 11 additions & 0 deletions src/main/java/calculator/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package calculator.view;

import static camp.nextstep.edu.missionutils.Console.readLine;

public class InputView {

public String getInput() {
return readLine();
}

}
15 changes: 15 additions & 0 deletions src/main/java/calculator/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package calculator.view;

import static calculator.common.constant.message.ViewMessages.CALCULATOR_RESULT_MESSAGE;
import static calculator.common.constant.message.ViewMessages.INPUT_PROMPT_MESSAGE;

public class OutputView {

public void printInputPrompt() {
System.out.println(INPUT_PROMPT_MESSAGE);
}

public void printResult(int result) {
System.out.println(CALCULATOR_RESULT_MESSAGE.formatted(result));
}
}
17 changes: 17 additions & 0 deletions src/test/java/calculator/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class ApplicationTest extends NsTest {

@Test
void 기본_구분자_사용() {
assertSimpleTest(() -> {
run("1,2,3");
assertThat(output()).contains("결과 : 6");
});
}

@Test
void 빈값_처리() {
assertSimpleTest(() -> {
run("\n");
assertThat(output()).contains("결과 : 0");
});
}

@Test
void 커스텀_구분자_사용() {
assertSimpleTest(() -> {
Expand Down