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

Step2 (사다리 생성) : 리뷰 요청드립니다. #413

Merged
merged 28 commits into from
Jun 7, 2020
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d39d67a
feat (Lambda & CarTest) : 람다 실습 기능 구현
xlffm3 Jun 3, 2020
220357c
feat (StreamStudy) : stream 실습 완료
xlffm3 Jun 3, 2020
8ae279b
feat (User & Expression) : Optional 실습
xlffm3 Jun 3, 2020
0958512
test & feat (Player) : 객체 생성 성공 및 실패에 대한 테스트와 예외 기능 추가
xlffm3 Jun 5, 2020
f37fb00
feat (InputView) : 유저 이름 입력 받는 기능 추가
xlffm3 Jun 5, 2020
b8d4a3a
test & feat (PlayersGroup) : Player 목록 일급 컬렉션 테스트 및 생성 기능 추가
xlffm3 Jun 5, 2020
5045f38
feat (InputView) : 사다리 길이 입력 기능 추가
xlffm3 Jun 5, 2020
2079132
refactor (InputView) : 상수 분리
xlffm3 Jun 5, 2020
827837b
test & feat (Line) : 생성 및 예외 테스트와 기능 추가
xlffm3 Jun 6, 2020
789f432
refactor (Line) : 예외처리 메소드 분리
xlffm3 Jun 6, 2020
da348aa
test & feat (Point) : 객체 구현
xlffm3 Jun 6, 2020
0d359af
test & feat (Line) : Line<Point>를 초기화하는 기능 구현
xlffm3 Jun 6, 2020
e943628
refactor (Line) : 정적 팩토리 메소드 추가
xlffm3 Jun 6, 2020
c278208
test & feat (DrawingLineStrategy) : 사람의 수에 비례해 라인을 그리는 기능 구현
xlffm3 Jun 7, 2020
2adc6fd
test & feat (Point) : 난수를 이용한 정적 팩토리 메소드 추가
xlffm3 Jun 7, 2020
10caac7
refactor (RandomDrawingLineStrategy) : 메소드 분리
xlffm3 Jun 7, 2020
802a180
test (DrawingLineStrategy) : 전략 테스트 추가
xlffm3 Jun 7, 2020
3d4b138
test & feat (Line) : Line 객체 생성 및 예외 발생 테스트 기능 구현
xlffm3 Jun 7, 2020
7687130
test & feat (PlayersGroup) : playerCounts 반환 기능 및 테스트 추가
xlffm3 Jun 7, 2020
d588560
test & feat (LadderFactory) : ladderFactory 객체 생성 및 예외 테스트 추가
xlffm3 Jun 7, 2020
91756bf
test & feat (Ladder) : 정적 팩토리를 통한 사다리 생성 기능 추가
xlffm3 Jun 7, 2020
8657821
test & feat (PlayersGroup) : 플레이어 명단(List<String>) 기능 테스트 및 구현
xlffm3 Jun 7, 2020
ac862a4
test & feat (OutputView & Ladder) : 참가자 명단 출력 기능 구현 및 사다리 정보 getter 기…
xlffm3 Jun 7, 2020
abd6382
feat & refactor (OutputView) : 사다리 출력 기능 구현 및 리팩토링(상수 분리)
xlffm3 Jun 7, 2020
4de92a9
refactor (Point & Line & Ladder) : 메소드명명 수정
xlffm3 Jun 7, 2020
2f232ec
style : 클래스 상수 개행 삭제 및 상수와 인스턴스 변수간 개행 추가
xlffm3 Jun 7, 2020
df6f938
feat (LadderBuildingException) : 커스텀 예외 구현
xlffm3 Jun 7, 2020
cc1bfa7
refactor (Line) : DrawingLineStrategy를 parameter로 주입받게 변경
xlffm3 Jun 7, 2020
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
19 changes: 19 additions & 0 deletions src/main/java/ladder/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ladder;

import ladder.domain.Ladder;
import ladder.domain.LadderFactory;
import ladder.domain.PlayersGroup;
import ladder.view.InputView;
import ladder.view.OutputView;

public class Application {

public static void main(String[] args) {
PlayersGroup playersGroup = PlayersGroup.of(InputView.inputPlayerNames());
LadderFactory ladderFactory = new LadderFactory(InputView.inputLadderHeight());
Ladder ladder = ladderFactory.buildLadder(playersGroup);

OutputView.printPlayerNames(playersGroup);
OutputView.printLadder(ladder);
}
}
48 changes: 48 additions & 0 deletions src/main/java/ladder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## 사다리 게임 구현 기능 목록

### Domain

* Player
* 게임 참가자 객체
* 이름에 대한 예외 처리
* 이름이 NULL이거나 빈 문자열이거나 5자를 넘는 경우 예외 발생

* PlayersGroup
* 게임 참가지 객체의 리스트(List<Player>) 일급 컬렉션
* 참가자 객체의 이름 목록을 파라미터로 받아 객체 생성
* Player들의 이름 명단(List<String>) 반환
* Player들 수를 반환

* Point
* 사다리 한 수평 라인의 한 점을 구성하는 객체
* 해당 부분에 값이 존재하는지 아닌지(boolean)를 결정함.
* 난수를 받아 객체 생성 시, 해당 부분에 값이 존재하는지 아닌지를 결정함.

* Line
* 사다리의 수평 라인 한 줄을 의미하는 객체
* 수평 라인이 존재하는 부분과 아닌 부분을 List<Point>으로 가짐
* 생성된 Line을 구성하는 각 Point들의 정보를 담은 List<Boolean> 반환

* DrawingLineStrategy
* 선을 그리는 전략 인터페이스
* RandomDrawingLineStrategy는 인자로 참가자의 수(사다리의 너비)를 받음.

* LadderFactory
* 게임 참가자 수와 Ladder 높이를 파라미터로 받아 적합한 크기의 Ladder 생성
* 높이가 1보다 작을 경우 예외 발생

* Ladder
* 사다리 2차원 배열의 정보를 List<Line>으로 가지고 있는 일급 컬렉션.
* 플레이어 명단과 사다리 높이를 바탕으로 사다리를 생성함.
* 사다리의 설계도면을 List<List<Boolean>>으로 반환함

### View

* InputView
* 쉼표로 구분되는 게임 참가자(Player) 명단을 입력 받음.
* 사다리 높이를 입력 받음.

* OutputView
* Ladder 객체를 바탕으로 사다리의 모습을 그림

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

import java.util.List;

public interface DrawingLineStrategy {

public List<Point> drawLine(int playerCounts);
}
11 changes: 11 additions & 0 deletions src/main/java/ladder/domain/ErrorMessages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ladder.domain;

public class ErrorMessages {

public static final String INVALID_PLAYER_NAME = "게임 참가자의 이름은 빈 문자열이 아닌 1 ~ 5자리의 문자만 가능합니다.";
public static final String INVALID_PLAYER_COUNTS = "게임 참가자는 1명 이상이어야 합니다.";
public static final String INVALID_LADDER_HEIGHT = "사다리 높이는 1 이상이어야 합니다.";
Copy link

Choose a reason for hiding this comment

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

이보다는 RuntimeException을 상속하여 에러를 정의한 클래스를 만들어서 사용해 보면 어떨까요?


private ErrorMessages() {
}
}
32 changes: 32 additions & 0 deletions src/main/java/ladder/domain/Ladder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ladder.domain;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Ladder {

private final List<Line> lines;

private Ladder(List<Line> lines) {
Copy link

Choose a reason for hiding this comment

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

생성자에서 DrawingLineStrategy를 받도록 처리해 주세요. 이렇게 처리해야 확장성이 높아집니다.

this.lines = lines;
}

public static Ladder buildLadder(PlayersGroup playersGroup, int ladderHeight) {
int playerCounts = playersGroup.getPlayerCounts();
List<Line> ladder = Stream.generate(() -> Line.drawLine(playerCounts))
.limit(ladderHeight)
.collect(Collectors.toList());
return new Ladder(ladder);
}

public List<List<Boolean>> getLadderBluePrint() {
return lines.stream()
.map(Line::getPointPositions)
.collect(Collectors.toList());
}

public int getLadderHeight() {
return lines.size();
}
}
22 changes: 22 additions & 0 deletions src/main/java/ladder/domain/LadderFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ladder.domain;

public class LadderFactory {

private static final int MINIMUM_LADDER_HEIGHT = 1;
Copy link

Choose a reason for hiding this comment

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

상수는 개행시켜주지 않으셔도 됩니다ㅎㅎ

private final int ladderHeight;
Copy link

Choose a reason for hiding this comment

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

필드 속성은 상수와 개행시켜 주세요!


public LadderFactory(int ladderHeight) {
validateLadderHeight(ladderHeight);
this.ladderHeight = ladderHeight;
}

private void validateLadderHeight(int ladderHeight) {
if (ladderHeight < MINIMUM_LADDER_HEIGHT) {
throw new IllegalArgumentException(ErrorMessages.INVALID_LADDER_HEIGHT);
}
}

public Ladder buildLadder(PlayersGroup playersGroup) {
return Ladder.buildLadder(playersGroup, ladderHeight);
}
}
37 changes: 37 additions & 0 deletions src/main/java/ladder/domain/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ladder.domain;

import java.util.List;
import java.util.stream.Collectors;

public class Line {

private static final int MINIMUM_PLAYER_COUNTS = 1;
private final List<Point> points;
Copy link

Choose a reason for hiding this comment

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

위의 코멘트와 동일한 컨벤션으로 변경시켜 주세요.

Copy link

Choose a reason for hiding this comment

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

다른 클래스도 모두 변경시켜 주세요!


private Line(List<Point> points) {
this.points = points;
}

public static Line drawLine(int playerCounts) {
validatePlayerCounts(playerCounts);
List<Point> points = drawLineWithStrategy(playerCounts, new RandomDrawingLineStrategy());
Copy link

Choose a reason for hiding this comment

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

인터페이스를 생성하신 부분 칭찬드립니다 👍
다만 전략 인터페이스는 조건 + 전략의 조합으로 이루어집니다. 때문에 지금 활용하신 부분은 인터페이스의 활용 정도로 생각해 주세요ㅎㅎ

Copy link

Choose a reason for hiding this comment

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

인터페이스를 활용해 주셨는데 인터페이스의 확장성은 열려있지 않습니다. 외부에서 어떠한 인터페이스를 사용할지 결정시켜 주어야 하는데 파라미터 혹은 생성자 파라미터로 의존성을 열어 주세요.
이와 같은 원리는 스프링의 DI와 일맥상통하니 참고하시기 바랍니다.

return new Line(points);
}

private static void validatePlayerCounts(int playerCounts) {
if (playerCounts < MINIMUM_PLAYER_COUNTS) {
throw new IllegalArgumentException(ErrorMessages.INVALID_PLAYER_COUNTS);
}
}

private static List<Point> drawLineWithStrategy(int playerCounts,
Copy link

Choose a reason for hiding this comment

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

불필요한 메서드로 보입니다. 이미 클래스로 충분히 설명되는것 같아요.

DrawingLineStrategy drawingLineStrategy) {
return drawingLineStrategy.drawLine(playerCounts);
}

public List<Boolean> getPointPositions() {
return points.stream()
.map(Point::getIsExisting)
.collect(Collectors.toList());
}
}
30 changes: 30 additions & 0 deletions src/main/java/ladder/domain/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ladder.domain;

public class Player {

private static final int MAXIMUM_NAME_LENGTH = 5;
private final String name;

public Player(String name) {
validateName(name);
this.name = name;
}

private void validateName(String name) {
if (isNullOrEmpty(name) || isInvalidLength(name)) {
throw new IllegalArgumentException(ErrorMessages.INVALID_PLAYER_NAME);
}
}

private boolean isNullOrEmpty(String name) {
return name == null || name.isEmpty();
}

private boolean isInvalidLength(String name) {
return name.length() > MAXIMUM_NAME_LENGTH;
}

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

import java.util.List;
import java.util.stream.Collectors;

public class PlayersGroup {

private final List<Player> players;

private PlayersGroup(List<Player> players) {
this.players = players;
}

public static PlayersGroup of(List<String> playerNames) {
List<Player> players = playerNames.stream()
.map(Player::new)
.collect(Collectors.toList());
return new PlayersGroup(players);
}

public List<String> getPlayerNames() {
return players.stream()
.map(Player::getName)
.collect(Collectors.toList());
}

public int getPlayerCounts() {
return players.size();
}
}
22 changes: 22 additions & 0 deletions src/main/java/ladder/domain/Point.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ladder.domain;

public class Point {

private static final int RANDOM_NUMBER_BOUNDARY = 5;
private final boolean isExisting;

public Point(boolean isExisting) {
this.isExisting = isExisting;
}

public static Point drawPoint(int randomNumber) {
if (randomNumber < RANDOM_NUMBER_BOUNDARY) {
return new Point(false);
}
return new Point(true);
}

public boolean getIsExisting() {
return isExisting;
}
}
46 changes: 46 additions & 0 deletions src/main/java/ladder/domain/RandomDrawingLineStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ladder.domain;

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

public class RandomDrawingLineStrategy implements DrawingLineStrategy {

private static final int LOOP_ZERO = 0;
private static final int LINE_WIDTH_CONSTANT = 1;
private static final int INDEX_CONSTANT = 1;
private static final int RANDOM_NUMBER_RANGE = 10;
private static final Random random = new Random();
Copy link

Choose a reason for hiding this comment

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

상수라면 변수명이 대문자여야 합니다.


@Override
public List<Point> drawLine(int playerCounts) {
List<Point> points = new ArrayList<>();
int lineWidth = playerCounts - LINE_WIDTH_CONSTANT;
for (int i = LOOP_ZERO; i < lineWidth; i++) {
Point point = drawPoint(points);
points.add(point);
}
return points;
}

private Point drawPoint(List<Point> points) {
int randomNumber = generateRandomNumber();
if (points.isEmpty()) {
return Point.drawPoint(randomNumber);
}
if (isLastPointExisting(points)) {
return new Point(false);
}
return Point.drawPoint(randomNumber);
}

private boolean isLastPointExisting(List<Point> points) {
int lastPointIndex = points.size() - INDEX_CONSTANT;
Point lastPoint = points.get(lastPointIndex);
return lastPoint.getIsExisting();
}

private int generateRandomNumber() {
return random.nextInt(RANDOM_NUMBER_RANGE);
}
}
24 changes: 24 additions & 0 deletions src/main/java/ladder/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ladder.view;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class InputView {

private static Scanner scanner = new Scanner(System.in);

private InputView() {
}

public static List<String> inputPlayerNames() {
System.out.println(ViewMessages.INSTRUCTION_PLAYER_NAMES);
String[] inputPlayerNames = scanner.nextLine().split(ViewMessages.COMMA);
return Arrays.asList(inputPlayerNames);
}

public static int inputLadderHeight() {
System.out.println(ViewMessages.INSTRUCTION_LADDER_HEIGHT);
return Integer.parseInt(scanner.nextLine());
}
}
Loading