-
Notifications
You must be signed in to change notification settings - Fork 744
3주차 - Step2 사다리(생성) 리뷰 요청드립니다. #198
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
Changes from all commits
75aecbb
2cbabd1
6aac283
c44d5e0
6dfa703
e6630ac
b6af3e3
7a883ad
8f016c1
595047f
5754205
d2c4d88
51fdfd5
db7fd55
31544a8
7570f85
54c6bef
23729f3
9b35290
a98d95c
36531ae
ea16228
d48e3c2
0184b02
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 |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package ladder; | ||
|
||
import ladder.domain.Height; | ||
import ladder.domain.Ladder; | ||
import ladder.domain.Players; | ||
import ladder.view.InputView; | ||
import ladder.view.OutputView; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
Players players = Players.of(InputView.askPlayers()); | ||
Height height = Height.from(InputView.askHeight()); | ||
|
||
Ladder ladder = Ladder.from(players, height); | ||
|
||
OutputView.printResult(players, ladder); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package ladder.domain; | ||
|
||
public interface BarGenerator { | ||
|
||
boolean generateBar(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Random; | ||
|
||
public class BarGeneratorImpl implements BarGenerator{ | ||
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. 클래스 이름의 'Impl'은 의미가 없습니다. 아래의 글을 읽고 코드에 반영하면 어떨까요? 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. 유익한 글 공유 감사합니다! 무의식적으로 Impl을 붙여왔었는데 잘못된 습관이었네요! 질문이 있습니다. 만약 비즈니스 로직이 BarGeneratorImpl 처럼 랜덤으로 Bars를 생성하는 경우 외에 다른 방법으로 Bars를 생성할 일이 없는 경우에도 인터페이스로 구현하는 것이 맞는지 궁금합니다.. 인터페이스로 빼야 될 것 같은 느낌(?) 때문에 인터페이스로 구현했는데 공유주신 글 내용중에
이런 내용이 있어서 BarGenerator를 인터페이스로 만들 필요가 있었는지 의문이 생겼습니다. 제가 인터페이스에 익숙하지 않아서 더더욱 헷갈리네요..ㅠ 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. 질문에 대한 답변은 Slack을 통해 남겼어요. 👍 |
||
|
||
private Random random = new Random(); | ||
|
||
@Override | ||
public boolean generateBar() { | ||
return random.nextBoolean(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package ladder.domain; | ||
|
||
public class Height { | ||
static final String ALERT_MINIMUM_LADDER_HEIGHT = "사다리의 최소 높이는 1입니다."; | ||
static final int MINIMUM_LADDER_HEIGHT = 1; | ||
|
||
private final int height; | ||
|
||
private Height(int inputHeight) { | ||
if (inputHeight < MINIMUM_LADDER_HEIGHT) { | ||
throw new IllegalArgumentException(ALERT_MINIMUM_LADDER_HEIGHT); | ||
} | ||
this.height = inputHeight; | ||
} | ||
|
||
public static Height from(int inputHeight) { | ||
return new Height(inputHeight); | ||
} | ||
|
||
public int getHeight() { | ||
return height; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
|
||
public class Ladder { | ||
|
||
private List<Line> lines; | ||
|
||
private Ladder(List<Line> lines) { | ||
this.lines = lines; | ||
} | ||
|
||
public static Ladder from(Players players, Height height) { | ||
return new Ladder(IntStream | ||
.range(0, height.getHeight()) | ||
.mapToObj((integer) -> Line.from(players.numberOfPlayers())) | ||
.collect(Collectors.toList())); | ||
} | ||
|
||
public List<Line> getLines() { | ||
return Collections.unmodifiableList(lines); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package ladder.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class Line { | ||
|
||
private List<Boolean> bars; | ||
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.
|
||
|
||
private Line(List<Boolean> bars) { | ||
this.bars = new ArrayList<>(bars); | ||
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 static Line from(int numberOfPlayers) { | ||
LineMaker lineMaker = new LineMaker(); | ||
return new Line(lineMaker.generateBars(numberOfPlayers)); | ||
} | ||
|
||
public List<Boolean> getBars() { | ||
return Collections.unmodifiableList(bars); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package ladder.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
class LineMaker { | ||
|
||
private List<Boolean> randomBars = new ArrayList<>(); | ||
private BarGeneratorImpl barGenerator = new BarGeneratorImpl(); | ||
|
||
List<Boolean> generateBars(int numberOfPlayers) { | ||
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. 이 메서드는 두 번 이상 사용할 수 있을까요? 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. 미처 생각하지 못한 부분인데 피드백주셔서 감사합니다!! 제가 이해한 바는, 이 메서드를 한 번 사용하고 나면 LineMaker 클래스의 인스턴스 변수 randomBars에 데이터가 박혀있기 때문에 다시 사용하면, 이전에 사용했던 randomBars에 bars를 추가하게 되므로 재사용할 수 없다고 이해했는데 맞을까요..? 그래서 class LineMaker {
private List<Bar> randomBars;
List<Bar> generateBars(int numberOfPlayers) {
this.randomBars = new ArrayList<>(); // 이 부분 추가
generateFirstBar();
generateMiddleBars(numberOfPlayers);
generateLastBar();
return randomBars;
}
...
} 위와 같이 generateBars메서드가 호출되면 randomBars가 초기화되도록 바꾸었는데 올바른 방법인지 궁금합니다..!! 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. 네, 맞습니다. 👍 |
||
randomBars.add(barGenerator.generateBar()); | ||
for (int i = 1; i < numberOfPlayers - 1; i++) { | ||
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.
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. for문은 첫번째 bar와 마지막 bar를 제외한 가운데 bars를 생성하는 부분이라서 혹시 피드백주신 부분에 대해 제가 이해한 바가 맞을까요? 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. 네, 맞습니다. 👍 |
||
boolean previousBarExist = randomBars.get(i - 1); | ||
addNextBar(previousBarExist); | ||
} | ||
addBlankBar(); | ||
return randomBars; | ||
} | ||
|
||
private void addNextBar(boolean previousBarExist) { | ||
if (previousBarExist) { | ||
addBlankBar(); | ||
return; | ||
} | ||
randomBars.add(barGenerator.generateBar()); | ||
} | ||
|
||
private void addBlankBar() { | ||
randomBars.add(false); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package ladder.domain; | ||
|
||
public class Player { | ||
private static final int MAXIMUM_NAME_LENGTH = 5; | ||
private static final String ALERT_EXCEED_OF_NAME_LENGTH = "이름은 최대 5글자까지 가능합니다."; | ||
private static final String ALERT_EMPTY_NAME = "이름은 최소 1글자 이상 입력하세요."; | ||
|
||
private final String name; | ||
|
||
private Player(String name) { | ||
validationPlayerName(name); | ||
this.name = name; | ||
} | ||
|
||
public static Player from(String name) { | ||
return new Player(name); | ||
} | ||
|
||
private void validationPlayerName(String name) { | ||
if (name.length() > MAXIMUM_NAME_LENGTH) { | ||
throw new IllegalArgumentException(ALERT_EXCEED_OF_NAME_LENGTH); | ||
} | ||
if ("".equals(name)) { | ||
throw new IllegalArgumentException(ALERT_EMPTY_NAME); | ||
} | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Player{" + | ||
"name='" + name + '\'' + | ||
'}'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Players { | ||
private static final String NAME_SEPARATOR = ","; | ||
private static final int MINIMUM_NUMBER_OF_PLAYERS = 2; | ||
private static final String ALERT_SHORTAGE_OF_NUMBER_OF_PLAYERS = "플레이어는 최소 2명이 필요합니다."; | ||
|
||
private final List<Player> players; | ||
|
||
private Players(List<Player> players) { | ||
if (players.size() < MINIMUM_NUMBER_OF_PLAYERS) { | ||
throw new IllegalArgumentException(ALERT_SHORTAGE_OF_NUMBER_OF_PLAYERS); | ||
} | ||
this.players = players; | ||
} | ||
|
||
public static Players of(String inputNames) { | ||
return new Players(Arrays.stream(inputNames.trim().split(NAME_SEPARATOR)) | ||
.map(String::trim) | ||
.map(Player::from) | ||
.collect(Collectors.toList())); | ||
} | ||
|
||
public int numberOfPlayers() { | ||
return players.size(); | ||
} | ||
|
||
public List<Player> getPlayers() { | ||
return Collections.unmodifiableList(players); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package ladder.view; | ||
|
||
import java.util.Scanner; | ||
|
||
public class InputView { | ||
private static final String MESSAGE_FOR_INPUT_PLAYER_NAMES = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; | ||
private static final String MESSAGE_FOR_MAXIMUM_LADDER_HEIGHT = "최대 사다리 높이는 몇 개인가요?"; | ||
|
||
private static Scanner scanner = new Scanner(System.in); | ||
|
||
public static String askPlayers() { | ||
System.out.println(MESSAGE_FOR_INPUT_PLAYER_NAMES); | ||
return scanner.nextLine(); | ||
} | ||
|
||
public static int askHeight() { | ||
printEmptyLine(); | ||
System.out.println(MESSAGE_FOR_MAXIMUM_LADDER_HEIGHT); | ||
return scanner.nextInt(); | ||
} | ||
|
||
static void printEmptyLine() { | ||
System.out.println(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package ladder.view; | ||
|
||
import ladder.domain.Ladder; | ||
import ladder.domain.Line; | ||
import ladder.domain.Player; | ||
import ladder.domain.Players; | ||
|
||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
|
||
import static ladder.view.InputView.printEmptyLine; | ||
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 class OutputView { | ||
private static final String MESSAGE_RESULT_TITLE = "실행결과"; | ||
private static final String EMPTY_SPACE = " "; | ||
private static final String BAR = "-----"; | ||
private static final String COLUMN = "|"; | ||
private static final String BLANK_TO_FILL_THE_NAME_SPACE = " "; | ||
private static final int SPACE_FOR_NAME = 5; | ||
|
||
public static void printResult(Players players, Ladder ladder) { | ||
printResultTitle(); | ||
printPlayers(players); | ||
printLadder(ladder); | ||
} | ||
|
||
private static void printResultTitle() { | ||
printEmptyLine(); | ||
System.out.println(MESSAGE_RESULT_TITLE); | ||
printEmptyLine(); | ||
} | ||
|
||
private static void printPlayers(Players players) { | ||
players.getPlayers().stream() | ||
.map(OutputView::adjustNameLength) | ||
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.
|
||
.forEach(System.out::print); | ||
printEmptyLine(); | ||
} | ||
|
||
private static String adjustNameLength(Player player) { | ||
String name = player.getName(); | ||
int spaceForBlank = SPACE_FOR_NAME - name.length(); | ||
|
||
return IntStream.rangeClosed(0, spaceForBlank) | ||
.mapToObj((integer) -> BLANK_TO_FILL_THE_NAME_SPACE) | ||
.collect(Collectors.joining()) | ||
.concat(name); | ||
} | ||
|
||
private static void printLadder(Ladder ladder) { | ||
ladder.getLines().forEach(OutputView::printLine); | ||
} | ||
|
||
private static void printLine(Line line) { | ||
System.out.print(EMPTY_SPACE); | ||
line.getBars().stream() | ||
.map(OutputView::printBars) | ||
.forEach(System.out::print); | ||
printEmptyLine(); | ||
} | ||
|
||
private static String printBars(Boolean bar) { | ||
StringBuilder stringBuilder = new StringBuilder(); | ||
stringBuilder.append(COLUMN); | ||
if (bar) { | ||
return stringBuilder.append(BAR).toString(); | ||
} | ||
return stringBuilder.append(EMPTY_SPACE).toString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package ladder.domain; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; | ||
|
||
public class HeightTest { | ||
@Test | ||
void 입력받은_사다리의_높이가_1보다_작을_경우_예외가_발생한다() { | ||
int inputHeight = Height.MINIMUM_LADDER_HEIGHT - 1; | ||
|
||
assertThatExceptionOfType(IllegalArgumentException.class) | ||
.isThrownBy(() -> { | ||
Height.from(inputHeight); | ||
}).withMessage(Height.ALERT_MINIMUM_LADDER_HEIGHT); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package ladder.domain; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class LadderTest { | ||
@Test | ||
void 입력된_사다리의_높이만큼_Line을_생성하여_사다리를_만든다() { | ||
int inputHeight = 5; | ||
Ladder ladder = Ladder.from(Players.of("test1,test2,test3"), Height.from(inputHeight)); | ||
|
||
assertThat(ladder.getLines().size()).isEqualTo(inputHeight); | ||
} | ||
} |
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.
BarGenerator
인터페이스 👍 이런 형태의 인터페이스를 함수형 인터페이스라고 부른답니다.@FunctionalInterface
가 무엇인지 찾아보고 공부해 보세요.Uh oh!
There was an error while loading. Please reload this page.
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.
@FunctionalInterface
어노테이션을 붙이면 개발자들이 함수형 인터페이스라는 것을 알 수 있고, 이 인터페이스가 오직 하나의 추상메서드만 가지는지 컴파일러가 체크할 수 있게 한다는 점을 알게 되었습니다-! 함수형 인터페이스 자체에 대해서도 더 깊게 공부해보겠습니다. 감사합니다! 👍