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 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
edc31fc
docs : README 기능구현 목록 작성
yeeun0702 May 5, 2024
a454554
feat: InputView, ResultView 구현
yeeun0702 May 5, 2024
b367140
test: 사람 이름 5글자 이상 예외 처리
sojeong0202 May 5, 2024
88b6b2b
feat: 사람 이름 5글자 이상 예외 처리 구현
sojeong0202 May 5, 2024
a49921e
test: 사람 이름 예외 처리 테스트 구현
sojeong0202 May 5, 2024
6afc0f5
feat: 사람 이름 예외 처리 구현
sojeong0202 May 5, 2024
0dd15bc
feat: 사다리 높이 예외 처리 테스트 구현
yeeun0702 May 5, 2024
c393e56
feat: 사다리 높이 예외 처리 구현
yeeun0702 May 5, 2024
065ab77
feat: Person, LadderMaker 예외처리 적용
yeeun0702 May 5, 2024
d48d812
test: PersonList 테스트 구현
sojeong0202 May 5, 2024
2b1b138
feat: PersonList 구현
sojeong0202 May 5, 2024
b5a1dde
test: 사다리 가로라인에서 True가 겹치면 재조정하는 메소드 테스트코드 구현
yeeun0702 May 6, 2024
9ec9c84
feat: Line 구현
yeeun0702 May 6, 2024
f064504
feat: Line 구현
yeeun0702 May 6, 2024
df1619c
test: 입력 받은 이름 재가공 메소드 테스트 구현
sojeong0202 May 8, 2024
6b7e70d
feat: 입력 받은 이름 재가공 하는 메소드 구현
sojeong0202 May 8, 2024
e48df59
feat: 정해진 조건대로 사람 이름출력
yeeun0702 May 8, 2024
5a2720c
feat: Controller 1차 구현
yeeun0702 May 8, 2024
5326a52
feat: 매개변수로 입력받은 불리언 리스트에 따라 사다리 출력 메소드 구현
sojeong0202 May 8, 2024
4b112ad
feat: controller 구현 완료
sojeong0202 May 8, 2024
314556b
style: 코드 포맷 변경
yeeun0702 May 8, 2024
2f6fbc8
refactor: PersonList를 분리하여 manipulationPeople과 PersonList를 일급 컬렉션으로 만듬
yeeun0702 May 11, 2024
59d40d4
refactor: 일급 컬렉션 적용 수정
yeeun0702 May 11, 2024
5ad3bcb
refactor: Line 클래스 분리
sojeong0202 May 11, 2024
d638722
style: 코드 컨벤션 적용
sojeong0202 May 11, 2024
6344529
refactor: LadderTest asserThatThrownBy() 사용하여 변경
yeeun0702 May 19, 2024
7c2631b
refactor: 들여쓰기가 2 이상인 메소드 분리
yeeun0702 May 19, 2024
af55f04
refactor: 일급컬렉션 이름 변경
yeeun0702 May 19, 2024
4751865
MVC 패턴에 맞추어 수정
yeeun0702 May 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
55 changes: 55 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## 기능 구현 목록

### Model
- [x] 사다리 라인(`|-----|`)
- [x] `true` 가로 작대기 있음
- [x] `false` 가로 작대기 없음
- [x] 사다리 maker
- [x] Boolean을 한 줄 랜덤하게 생성
- [x] 랜덤 생성한 Boolean line을 가로라인이 이웃끼리 겹치지 않도록 조정
- [x] 사다리 높이 예외처리(0을 제외한 숫자만 가능)
- [x] 사람
- [x] 입력조건 예외처리
- [x] 이름 리스트를 형식에 맞게 공백 넣어주기

### View
#### 입력 조건
- [x] 사람 이름 입력하기
- [x] 최대 5글자 (사람 이름이 5글자 이하라면 공백문자로 채워줘야 함)
- [x] 쉼표 기준으로 입력받기
- [x] 첫 번째 사람인 경우에, 이름이 5글자 이하여도 여백을 공백문자로 채우지 않음
- [x] 사다리 높이 입력받기
- [x] 숫자만 입력받기 (공백 or 문자가 입력될 경우 예외처리)

#### 출력 조건
- [x] 이름이 5글자일 경우, 이름의 끝 글자를 기준으로 입력 받은 높이만큼 사다리의 세로 라인 출력
- [x] 이름이 5글자 이하인 경우, 이름의 끝 글자 + 공백문자를 기준으로 입력 받은 높이만큼 사다리의 세로 라인 출력
- [x] 사다리가 정상적으로 작동하려면 가로 라인이 겹치지 않게 하기(ex.`|-----|-----|`)
- x] 사다리 라인(`|-----|`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소하지만 오타는 가독성을 해치곤 합니다. 다음부턴 신경써주세요! 😁

- [x] `true` -> `-----|`
- [x] `false` -> ` |`

### Controller
- [x] 사다리 타리 진행

---
# 요구사항
사다리 타기 미션 저장소
- 사다리 게임에 참여하는 사람의 이름을 최대 5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다.
- 사람 이름은 쉼표(,)를 기준으로 구분한다.
- 사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다.
- 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다.
- `|-----|-----|` 모양과 같이 가로 라인이 겹치는 경우 어느 방향으로 이동할지 결정할 수 없다.

### 추가된 요구 사항
- 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외
- 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
- UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.
- 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다.
- 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- 배열 대신 컬렉션을 사용한다.
- Java Enum을 적용한다.
- 모든 원시 값과 문자열을 포장한다
- 줄여 쓰지 않는다(축약 금지).
- 일급 컬렉션을 쓴다.
-

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요구 사항 정리 👍

13 changes: 13 additions & 0 deletions src/main/java/ladder/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ladder;

import ladder.controller.LadderController;
import ladder.view.InputView;
import ladder.view.ResultView;

public class Application {

public static void main(String[] args) {
LadderController ladderController = new LadderController(new InputView(), new ResultView());
ladderController.start();
}
}
45 changes: 45 additions & 0 deletions src/main/java/ladder/controller/LadderController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ladder.controller;

import java.util.List;
import ladder.model.LadderMaker;
import ladder.model.ManipulationPeople;
import ladder.model.PersonList;
import ladder.view.InputView;
import ladder.view.ResultView;

public class LadderController {

private final ResultView resultView;
private final InputView inputView;
private ManipulationPeople manipulationPeople;
private LadderMaker ladderMaker;


public LadderController(InputView inputview, ResultView resultView) {
this.inputView = inputview;
this.resultView = resultView;
}

public void start() {
resultView.startMessage();
this.manipulationPeople = new ManipulationPeople(new PersonList(inputView.inputName()).getPeople());

resultView.ladderHeightMessage();
this.ladderMaker = new LadderMaker(inputView.inputLadderHeight());

resultView.resultMessage();
resultView.printPeople(manipulationPeople.getManipulationPeopleNames());

for (int i = 0; i < ladderMaker.getLadderHeight(); i++) {
resultView.printLine(getFirstManipulationName(), getPeopleSize());
}
}

private List<Boolean> getPeopleSize() {
return ladderMaker.makeLadder(manipulationPeople.getManipulationPeopleNames().size());
}

private String getFirstManipulationName() {
return manipulationPeople.getManipulationPeopleNames().get(0);
}
}
26 changes: 26 additions & 0 deletions src/main/java/ladder/model/LadderMaker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ladder.model;

import java.util.List;
import ladder.util.validator.LadderValidator;

public class LadderMaker {

private int ladderHeight;

public LadderMaker(String ladderHeight) {
LadderValidator.checkEmpty(ladderHeight);
LadderValidator.checkLadderNumberStandard(ladderHeight);

this.ladderHeight = Integer.parseInt(ladderHeight);
}

public int getLadderHeight() {
return ladderHeight;
}

public List<Boolean> makeLadder(int personCount) {
RandomBoolean randomBoolean = new RandomBoolean();
Line lines = new Line(randomBoolean.createRandomColumn(personCount));
return lines.getPoints();
}
}
Comment on lines +6 to +26

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스의 이름이 LadderMaker였어야 할까요? List<Line>을 가진 LadderLines였다면 어땠을까요?
사람 수만큼 여러 라인들을 생성하고 조립하여 하나의 사다리를 만드는 일급 컬렉션으로 볼 수 있지 않을까요?

30 changes: 30 additions & 0 deletions src/main/java/ladder/model/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ladder.model;

import java.util.List;

public class Line {

private RandomBoolean randomBoolean = new RandomBoolean();

private List<Boolean> points;

public Line (List<Boolean> randomColumn) {
this.points = randomColumn;
rearrange(points);
}

public List<Boolean> getPoints() {
return points;
}

private void rearrange(List<Boolean> columns) {
boolean previousColumn = false;
for (int i = 0; i < columns.size(); i++) {
boolean currentColum = columns.get(i);
if (previousColumn == currentColum){
columns.set(i, false);
}
previousColumn = currentColum;
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컨벤션 상, rearRange가 더 어울리는 이름이 아닐까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요구 사항에도 적혀있지만 이번 미션에서는 indent(들여쓰기)를 1로 제한하고 있습니다.
해당 메소드는 indent가 2까지 내려가있습니다. 리팩토링 해볼까요?

힌트를 드리자면, 메소드 분리 혹은 로직 자체의 리팩토링이 방법이 될 수 있습니다.
구현이 어렵더라도 습관적으로 indent를 줄이려고 노력해야 합니다. (indent는 가독성에 큰 영향을 미칩니다.)

44 changes: 44 additions & 0 deletions src/main/java/ladder/model/ManipulationPeople.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ladder.model;

import java.util.ArrayList;
import java.util.List;

public class ManipulationPeople {

private static final int BLOCK_DIGIT = 6;
private static final int MAX_NAME_DIGIT = 5;
private final List<String> manipulationPeopleNames = new ArrayList<>();

public ManipulationPeople(List<Person> personList) {
manipulateNames(personList);
}

public List<String> getManipulationPeopleNames() {
return manipulationPeopleNames;
}

private void manipulateNames(List<Person> personList) {
for (Person person : personList) {
manipulationPeopleNames.add(manipulateNameBlank(person.getName()));
}
}

private String manipulateNameBlank(String name) {
int blankNumber = BLOCK_DIGIT - name.length();
StringBuilder manipultionName = new StringBuilder();

if (name.length() == MAX_NAME_DIGIT) {
manipultionName.append(" ");
}

for (int i = 0; i < blankNumber - 1; i++) {
manipultionName.append(" ");
}
manipultionName.append(name);

if (name.length() != MAX_NAME_DIGIT) {
manipultionName.append(" ");
}
return manipultionName.toString();
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View에 가까운 클래스라고 생각됩니다. model 패키지에 있기에는 조금 어색해보여요.

19 changes: 19 additions & 0 deletions src/main/java/ladder/model/Person.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ladder.model;

import ladder.util.validator.PersonValidator;

public class Person {

private String name;

public Person(String name) {
PersonValidator.checkEmpty(name);
PersonValidator.checkOverRange(name);
PersonValidator.checkSpace(name);
this.name = name;
}

public String getName() {
return name;
}
}
27 changes: 27 additions & 0 deletions src/main/java/ladder/model/PersonList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ladder.model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import ladder.util.validator.PersonValidator;

public class PersonList {

private List<Person> people = new ArrayList<>();

public PersonList(String nameList) {
PersonValidator.checkDuplicate(nameList);
personNameInput(nameList);
}

public List<Person> getPeople(){
return Collections.unmodifiableList(people);
}

private void personNameInput(String nameList) {
for (String personName : Arrays.asList(nameList.split(","))) {
people.add(new Person(personName));
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일급 컬렉션을 잘 구현하셨네요! 다만, 관례상 일급 컬렉션은 List로 가지고 있는 단일 클래스의 복수형으로 작성합니다.
단, 문법을 지켜가며 복수형으로 적진 않고, Persons처럼 단순히 -s-es를 붙입니다.

20 changes: 20 additions & 0 deletions src/main/java/ladder/model/RandomBoolean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ladder.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class RandomBoolean {
public List<Boolean> createRandomColumn(int personCount) {
List<Boolean> columns = new ArrayList<>();
for (int i = 0; i < personCount - 1; i++) {
columns.add(getRandomBoolean());
}
return columns;
}

private boolean getRandomBoolean() {
Random random = new Random();
return random.nextBoolean();
}
}
15 changes: 15 additions & 0 deletions src/main/java/ladder/util/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ladder.util;

public enum ErrorMessage {

INPUT_STRING_DUPLICATE("입력 값이 중복되었습니다."),
INPUT_STRING_NOT_NULL(" null이 될 수 없습니다."),
INPUT_PERSON_NAME_IS_INCORRECT("입력한 사람 이름이 올바르지 않습니다."),
INPUT_STRING_BLANK("입력 값은 공백이 될 수 없습니다."),
INPUT_LADDER_NUMBER("입력된 숫자가 조건에 맞지 않습니다.");
public final String message;

ErrorMessage(String message) {
this.message = message;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마찬가지로 이 클래스도 View에 가까워보입니다!

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

import java.util.regex.Pattern;
import ladder.util.ErrorMessage;

public class LadderValidator {

public static void checkEmpty(String input) {
if (input == null) {
throw new IllegalArgumentException(ErrorMessage.INPUT_STRING_NOT_NULL.message);
}
}

public static void checkLadderNumberStandard(String input) {
if (!isRightLadderNumber(input)) {
throw new IllegalArgumentException(ErrorMessage.INPUT_LADDER_NUMBER.message);
}
}

private static boolean isRightLadderNumber(String input) {
return Pattern.matches("^[1-9]\\d*$", input);
}
}
62 changes: 62 additions & 0 deletions src/main/java/ladder/util/validator/PersonValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ladder.util.validator;

import static ladder.util.ErrorMessage.INPUT_PERSON_NAME_IS_INCORRECT;
import static ladder.util.ErrorMessage.INPUT_STRING_BLANK;
import static ladder.util.ErrorMessage.INPUT_STRING_DUPLICATE;
import static ladder.util.ErrorMessage.INPUT_STRING_NOT_NULL;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enumstatic import는 가독성을 해친다는 의견이 있습니다. 읽기 어렵다기 보단 이해하기 어렵다는 의미의 가독성인데, 도대체 이 상수들이 어디서 온 건지를 코드만 읽어서는 알기 힘들다고 합니다.

리팩토링을 해야 하는 건 아니고, 알아 두시면 좋을 것 같습니다.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

public class PersonValidator {

private static final int MAX_DIGIT_PERSON_NAME = 5;
private static final int MIN_DIGIT_PERSON_NAME = 1;

public static void checkOverRange(String input) {
if (isOverRange(input) || isUnderRange(input)) {
throw new IllegalArgumentException(INPUT_PERSON_NAME_IS_INCORRECT.message);
}
}

public static void checkSpace(String input) {
if (isSpace(input)) {
throw new IllegalArgumentException(INPUT_STRING_BLANK.message);
}
}

public static void checkEmpty(String input) {
if (input == null) {
throw new IllegalArgumentException(INPUT_STRING_NOT_NULL.message);
}
}

public static void checkDuplicate(String input) {
if (hasDuplicatePersonName(input)) {
throw new IllegalArgumentException(INPUT_STRING_DUPLICATE.message);
}
}

private static boolean isOverRange(String input) {
return MAX_DIGIT_PERSON_NAME < input.length();
}

private static boolean isUnderRange(String input) {
return MIN_DIGIT_PERSON_NAME > input.length();
}

private static boolean isSpace(String input) {
return Pattern.matches("^\\s+$", input);
}

private static boolean hasDuplicatePersonName(String input) {
List<String> allPersonNames = new ArrayList<>(Arrays.asList(input.split(",")));
Set set = new HashSet(allPersonNames);

return allPersonNames.size() != set.size();
}
}
Loading