-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[문자열 덧셈 계산기] 민경태 미션 제출합니다. #1914
base: main
Are you sure you want to change the base?
Changes from all commits
e81bf33
2047172
d6b8224
54a553d
e482abc
bbe1a9b
34ab00f
5d7cf65
05084c0
85820c0
3db0f08
685a57a
987c91c
c932d2c
0f01bc4
eb937f1
d6a3161
5efe9f2
bebc033
f192a39
93dc649
dde4daa
1026689
9253888
1d200a7
a801593
050b645
f9c80d1
c90a512
9aad1c3
c3dbbc0
bdc59bb
4115bc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,57 @@ | ||
# java-calculator-precourse | ||
# java-calculator-precourse | ||
## 기능 구현 목록 | ||
입력한 문자열에서 숫자를 추출하여 더하는 계산기를 구현한다. | ||
|
||
### 입력 | ||
- [X] 유저의 입력을 전달한다. | ||
|
||
### 입력값 검사기 | ||
- 커스텀 구분자가 있는 입력일 때 | ||
- [X] 커스텀 구분자가 `//`로 시작해 `\n`가 포함되는지 확인한다. | ||
- [X] 커스텀 구분자가 길이가 1이 아니라면 예외 처리한다. | ||
- [X] 커스텀 구분자가 숫자라면 예외 처리한다. | ||
- [X] 커스텀 구분자가 실수를 표현하는 `.`라면 예외 처리한다. | ||
- [X] 커스텀 구분자가 기본 구분자라면 예외 처리 한다. | ||
|
||
|
||
- 커스텀 구분자가 없을 입력일 때 | ||
- [X] 입력값이 숫자로 시작하는 지 확인한다. | ||
|
||
|
||
- 공통 | ||
- [X] 커스텀 구분자를 입력하려는지 확인한다. | ||
- [X] 음수가 입력되었다면 예외 처리 한다. | ||
- [X] 구분자, `.`, 숫자 외 문자가 검출 된다면 예외 처리한다. | ||
|
||
### 구분자 관리 | ||
- [X] 기본 구분자 외 커스텀 구분자를 전달받아 추가한다. | ||
- [X] 전달받은 구분자가 기본(이미 존재하는지) 구분자인지 확인한다. | ||
- [X] 구분자를 넘겨준다. | ||
|
||
### 문자열 핸들러 | ||
- [X] 커스텀 구분자를 선언한다면 분리한다. | ||
- [X] 분리한 커스텀 구분자를 넘겨준다. | ||
- [X] 전달받은 구분자로 입력받은 문자열을 분리한다. | ||
|
||
### 덧셈기 | ||
- [X] 전달 받은 값을 더해 저장한다. | ||
- [X] 저장한 결과 값을 전달한다. | ||
- [X] 입력값이 출력 범위를 초과한다면 예외 처리한다. | ||
- [X] 더한 값이 출력 범위를 초과한다면 예외 처리한다. | ||
|
||
### 출력 | ||
- [X] 시작 메세지를 출력한다. | ||
- [X] 결과값을 출력한다. | ||
|
||
--- | ||
## 리팩토링 | ||
|
||
- [X] 하드 코딩 제거 | ||
- [X] 코딩 컨벤션 준수 | ||
- [X] 이상한 수식 넣었을 때 에러 | ||
``` | ||
덧셈할 문자열을 입력해 주세요. | ||
//;\n112kio12u328948 | ||
Exception in thread "main" java.lang.NumberFormatException: For input string: "112kio12u328948" | ||
``` | ||
- [ ] 기능 쪼개기 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제출을 완료했는데도 체크가 안된 체크 박스가 있는 건 왜일까요? 👀 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package calculator; | ||
|
||
import calculator.util.Adder; | ||
import calculator.util.SeparatorManager; | ||
import calculator.util.StringHandler; | ||
import calculator.util.Validator; | ||
import java.util.List; | ||
|
||
public class Controller { | ||
Input input = new Input(); | ||
Output output = new Output(); | ||
SeparatorManager separatorManager = new SeparatorManager(); | ||
StringHandler stringHandler = new StringHandler(); | ||
Validator validator = new Validator(); | ||
Adder adder = new Adder(); | ||
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스 내부에서 객체를 생성하면 어떤 단점이 있을까요 ?? 관련해서 의존성 주입을 참고해보시면 좋을것 같아요 ㅎㅎ
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컨트롤러에서 많은 객체를 생성해주고 있네요. 클래스 내부에서 객체를 직접 생성하면 생기는 단점은 차치하고서라도, 다른 단점은 있을 수 없을까요? |
||
|
||
public void start() { | ||
output.printStart(); | ||
String userInput = input.readInput(); | ||
validator.validateInput(userInput); | ||
|
||
if (validator.hasCustomSeparator(userInput)) { | ||
String separator = stringHandler.extractSeparator(userInput); | ||
validator.validateSeparator(separator); | ||
separatorManager.add(separator); | ||
String rawNumbers = stringHandler.removeCustom(userInput); | ||
List<String> numbers = stringHandler.getNumbers( | ||
separatorManager.getSeparators(), | ||
rawNumbers); | ||
adder.add(numbers); | ||
output.printResult(adder.getAnswer()); | ||
return; | ||
} | ||
|
||
if (validator.isStartWithDigit(userInput)) { | ||
List<String> numbers = stringHandler.getNumbers( | ||
separatorManager.getSeparators(), | ||
userInput | ||
); | ||
adder.add(numbers); | ||
output.printResult(adder.getAnswer()); | ||
return; | ||
} | ||
output.printResult(adder.getAnswer()); | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. InputView가 저도 이러한 방식으로 구현했는데요~ 근데 피드백으로 사용자에게 입력을 받을때 출력하는 문구는 InputView의 책임이 아닌가 하는 의견을 들었습니다~ 이 부분에 대해서 저는 아직도 해답을 찾지 못했는데, 경태님의 생각은 어떠신지 궁금해요! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package calculator; | ||
|
||
import camp.nextstep.edu.missionutils.Console; | ||
|
||
public class Input { | ||
public String readInput() { | ||
return Console.readLine(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package calculator; | ||
|
||
public class Output { | ||
public void printStart() { | ||
System.out.println("덧셈할 문자열을 입력해 주세요."); | ||
} | ||
|
||
public void printResult(long result) { | ||
System.out.println("결과 : " + result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package calculator.util; | ||
|
||
import java.util.List; | ||
|
||
public class Adder { | ||
long answer; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
이때 발생할 수 있는 문제는 없을까요? 🤔 |
||
|
||
public void add(List<String> numbers) { | ||
answer = 0; | ||
for (String number: numbers) { | ||
if (number.isBlank()) { | ||
continue; | ||
} | ||
validateNumber(number); | ||
long element = Long.parseLong(number); | ||
validateOverflow(element); | ||
answer += element; | ||
} | ||
validateOverflow(answer); | ||
} | ||
|
||
public long getAnswer() { | ||
return answer; | ||
} | ||
|
||
private void validateOverflow(long number) { | ||
if (number < 0) { | ||
throw new IllegalArgumentException("허용 범위를 초과하였습니다."); | ||
} | ||
} | ||
|
||
private void validateNumber(String number) { | ||
for (int i = 0; i < number.length(); i++) { | ||
if (!Character.isDigit(number.charAt(i))) { | ||
throw new IllegalArgumentException("등록된 구분자가 아닙니다."); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package calculator.util; | ||
|
||
import java.util.List; | ||
|
||
public class Constants { | ||
public static final String CUSTOM_PREFIX = "//"; | ||
public static final String CUSTOM_SUFFIX = "\\n"; | ||
public static final int SEPARATOR_LENGTH = 1; | ||
public static final String DECIMAL_POINT = "."; | ||
public static final List<String> DEFAULT_SEPARATORS = List.of(":", ","); | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요고는 필드에 상태를 안져도 괜찮을것 같은데, 경태님 생각은 어떠신가요 ?? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package calculator.util; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class SeparatorManager { | ||
List<String> separators; | ||
|
||
public SeparatorManager() { | ||
this.separators = new ArrayList<>(Constants.DEFAULT_SEPARATORS); | ||
} | ||
|
||
private boolean exists(String separator) { | ||
return separators.contains(separator); | ||
} | ||
|
||
public void add(String separator) { | ||
if (this.exists(separator)) { | ||
throw new IllegalArgumentException("이미 존재하는 구분자입니다."); | ||
} | ||
separators.add(separator); | ||
} | ||
|
||
public List<String> getSeparators() { | ||
return Collections.unmodifiableList(separators); | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 깔끔 합니다 👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package calculator.util; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class StringHandler { | ||
public String extractSeparator(String input) { | ||
int start = Constants.CUSTOM_PREFIX.length() ; | ||
int end = input.indexOf(Constants.CUSTOM_SUFFIX); | ||
return input.substring(start, end); | ||
} | ||
|
||
public List<String> getNumbers(List<String> separators, String input) { | ||
List<String> splitInput = new ArrayList<>(); | ||
splitInput.add(input); | ||
|
||
for (String separator : separators) { | ||
splitInput = splitBySeparator(splitInput, separator); | ||
} | ||
|
||
return splitInput; | ||
} | ||
|
||
private List<String> splitBySeparator(List<String> inputList, String separator) { | ||
List<String> result = new ArrayList<>(); | ||
|
||
for (String part : inputList) { | ||
String[] splitParts = part.split(separator); | ||
result.addAll(Arrays.asList(splitParts)); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
public String removeCustom(String input) { | ||
int numberIndex = input.indexOf(Constants.CUSTOM_SUFFIX) + 2; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기의 "2"는 상수로 관리하지 않고 있는 이유가 있나요? |
||
return input.substring(numberIndex); | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 클래스에 있는 메서드들을 static으로 선언하면 재사용하기 더 좋을것 같아요~ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package calculator.util; | ||
|
||
public class Validator { | ||
public boolean hasCustomSeparator(String input) { | ||
if (isEmpty(input)) { | ||
return false; | ||
} | ||
return input.startsWith(Constants.CUSTOM_PREFIX) && input.contains(Constants.CUSTOM_SUFFIX); | ||
} | ||
|
||
public boolean isStartWithDigit(String input) { | ||
if (isEmpty(input)) { | ||
return false; | ||
} | ||
return Character.isDigit(input.charAt(0)); | ||
} | ||
|
||
public boolean isEmpty(String input) { | ||
return input == null || input.isBlank(); | ||
} | ||
|
||
public void validateSeparator(String separator) { | ||
if (separator.length() != Constants.SEPARATOR_LENGTH) { | ||
throw new IllegalArgumentException("구분자의 길이는 1이어야 합니다."); | ||
} | ||
if (separator.equals(Constants.DECIMAL_POINT)) { | ||
throw new IllegalArgumentException(".은 구분자가 될 수 없습니다."); | ||
} | ||
if (isStartWithDigit(separator)) { | ||
throw new IllegalArgumentException("숫자는 구분자가 될 수 없습니다."); | ||
} | ||
} | ||
|
||
public void validateInput(String input) { | ||
if (isEmpty(input)) { | ||
return; | ||
} | ||
if (hasCustomSeparator(input)) { | ||
return; | ||
} | ||
if (isStartWithDigit(input)) { | ||
if ((!input.contains(Constants.CUSTOM_PREFIX) && !input.contains(Constants.CUSTOM_SUFFIX))) { | ||
return; | ||
} | ||
} | ||
throw new IllegalArgumentException("포멧에 맞게 입력해 주세요.(ex://@\\n1@2:3,4)"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package calculator; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
import calculator.util.Adder; | ||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
|
||
class AdderTest { | ||
Adder adder = new Adder(); | ||
|
||
@Test | ||
void 공백일때_0을_return_하는지() { | ||
adder.add(List.of("")); | ||
assertEquals(0, adder.getAnswer()); | ||
} | ||
|
||
@Test | ||
void 오버플로우_발생시_예외_처리() { | ||
assertThatThrownBy(() ->adder.add(List.of(String.valueOf(Double.MAX_VALUE),"1"))) | ||
.isInstanceOf(IllegalArgumentException.class); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package calculator; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; | ||
|
||
import calculator.util.SeparatorManager; | ||
import org.junit.jupiter.api.Test; | ||
|
||
class SeparatorManagerTest { | ||
SeparatorManager separatorManager = new SeparatorManager(); | ||
|
||
@Test | ||
void 이미_있는_구분자라면_예외_처리() { | ||
assertThatThrownBy(() -> separatorManager.add(":")) | ||
.isInstanceOf(IllegalArgumentException.class); | ||
} | ||
|
||
@Test | ||
void 없는_구분자라면_정상_작동() { | ||
assertThatCode(() -> separatorManager.add(";")) | ||
.doesNotThrowAnyException(); | ||
} | ||
|
||
@Test | ||
void 받은_구분자_리스트의_수정_불가한지_확인() { | ||
assertThatThrownBy(() -> separatorManager.getSeparators().remove(0)) | ||
.isInstanceOf(UnsupportedOperationException.class); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
문서도 꼼꼼하게 적어주셨고,
기능마다 체크 표시도 해주셨네요 👍
살아있는 문서화 좋습니다!