-
Notifications
You must be signed in to change notification settings - Fork 250
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
[1단계 사다리 생성] 다즐(최우창) 미션 제출합니다. #70
Changes from all commits
374f493
00e2f5a
cdfb0e0
816fdc4
9176b1e
3b0a1bc
0961c8f
599438a
495c9a5
7298261
d8a9c35
af94afb
20ae067
c143e85
b8f3a18
147d7cb
094df09
87efb38
84fa42a
2f27677
172394f
0d89856
3cd6d4b
c49a5fa
90fcb7a
6d26352
3a521e5
72cb897
5f1752f
9cba752
3af9db2
3baf790
a1fc51b
8531b23
79a8148
bb70ff7
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 java.util.Scanner; | ||
import ladder.controller.LadderController; | ||
import ladder.domain.generator.LadderGenerator; | ||
import ladder.view.InputView; | ||
import ladder.view.OutputView; | ||
|
||
public class LadderApplication { | ||
|
||
public static void main(String[] args) { | ||
final var inputView = new InputView(new Scanner(System.in)); | ||
final var outputView = new OutputView(); | ||
final var ladderGenerator = new LadderGenerator(); | ||
|
||
LadderController ladderController = new LadderController(inputView, outputView, ladderGenerator); | ||
ladderController.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package ladder.controller; | ||
|
||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
import ladder.domain.Height; | ||
import ladder.domain.Ladder; | ||
import ladder.domain.Players; | ||
import ladder.domain.generator.LadderGenerator; | ||
import ladder.domain.generator.LineGenerator; | ||
import ladder.view.InputView; | ||
import ladder.view.OutputView; | ||
|
||
public class LadderController { | ||
|
||
private final InputView inputView; | ||
private final OutputView outputView; | ||
private final LadderGenerator ladderGenerator; | ||
|
||
public LadderController(final InputView inputView, final OutputView outputView, | ||
final LadderGenerator ladderGenerator) { | ||
this.inputView = inputView; | ||
this.outputView = outputView; | ||
this.ladderGenerator = ladderGenerator; | ||
} | ||
|
||
public void run() { | ||
final Players players = generate(inputView::readPlayerNames, Players::new); | ||
final Height height = generate(inputView::readHeight, Height::new); | ||
final Ladder ladder = ladderGenerator.generate(new LineGenerator(), players, height); | ||
outputView.printLadderResult(players, ladder); | ||
} | ||
|
||
private <T, R> R generate(final Supplier<T> supplier, final Function<T, R> function) { | ||
try { | ||
return function.apply(supplier.get()); | ||
} catch (IllegalArgumentException e) { | ||
outputView.printErrorMessage(e.getMessage()); | ||
return generate(supplier, function); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum Direction { | ||
|
||
LEFT(-1, "-----"), | ||
STAY(0, " "), | ||
RIGHT(1, " "), | ||
; | ||
|
||
private final int move; | ||
private final String foothold; | ||
|
||
Direction(final int move, final String foothold) { | ||
this.move = move; | ||
this.foothold = foothold; | ||
} | ||
|
||
public static Direction from(final int value) { | ||
return Arrays.stream(Direction.values()) | ||
.filter(direction -> direction.getMove() == value) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 값입니다.")); | ||
} | ||
Comment on lines
+20
to
+25
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. 매번 stream을 열어줘야 하는걸까요 ? 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. 해당 로직을 static화 해보는게 어떨지 말씀드린거였어요 :) |
||
|
||
public int getMove() { | ||
return move; | ||
} | ||
|
||
public String getFoothold() { | ||
return foothold; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package ladder.domain; | ||
|
||
public class Height { | ||
|
||
private static final int MINIMUM_HEIGHT = 2; | ||
private static final int MAXIMUM_HEIGHT = 10; | ||
|
||
private final int value; | ||
|
||
public Height(final int value) { | ||
validate(value); | ||
this.value = value; | ||
} | ||
|
||
private void validate(final int value) { | ||
if (hasShort(value) || hasLong(value)) { | ||
throw new IllegalArgumentException("높이는 " + MINIMUM_HEIGHT + "이상, " + MAXIMUM_HEIGHT + "이하여야 합니다." | ||
+ " 현재 높이는 " + value + "입니다."); | ||
} | ||
} | ||
|
||
private boolean hasShort(final int value) { | ||
return value < MINIMUM_HEIGHT; | ||
} | ||
|
||
private boolean hasLong(final int value) { | ||
return MAXIMUM_HEIGHT < value; | ||
} | ||
|
||
public int getValue() { | ||
return value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class Ladder { | ||
|
||
private final List<Line> lines; | ||
|
||
public Ladder(final List<Line> lines) { | ||
this.lines = lines; | ||
} | ||
|
||
public List<Line> getLines() { | ||
return Collections.unmodifiableList(lines); | ||
} | ||
} | ||
Comment on lines
+14
to
+17
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. 저도 상태를 그대로 반환하는 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. VO를 DTO로 쓴다! 라고 한다면 지금과 같이 작성되어도 문제없을 것 같아요 :) |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package ladder.domain; | ||
|
||
import java.util.List; | ||
|
||
public class Line { | ||
|
||
private final List<Direction> directions; | ||
|
||
public Line(final List<Direction> directions) { | ||
this.directions = directions; | ||
} | ||
|
||
public List<Direction> getDirections() { | ||
return directions; | ||
} | ||
} | ||
Comment on lines
+5
to
+16
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. Line의 책임은, 정말 상태를 그대를 노출하는 것 뿐일까요? 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. Line이 foothold를 가지는건 어떨까요? Direction에 UI를 위한 String이 포함되는게 좋아보이진 않아서요 :) |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,63 @@ | ||||||||||||||||||||||||||
package ladder.domain; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import java.util.Objects; | ||||||||||||||||||||||||||
import java.util.regex.Pattern; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public class Name { | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private static final Pattern NAME_FORMAT = Pattern.compile("[a-zA-Z]+"); | ||||||||||||||||||||||||||
private static final int NAME_MAX_LENGTH = 5; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private final String value; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public Name(final String value) { | ||||||||||||||||||||||||||
validate(value); | ||||||||||||||||||||||||||
this.value = value; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private void validate(final String value) { | ||||||||||||||||||||||||||
validateFormat(value); | ||||||||||||||||||||||||||
validateLength(value); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
Comment on lines
+18
to
+21
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.
Suggested change
argument가 1개일 경우에는 string 연산을 사용해주세요. 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 void validateFormat(final String value) { | ||||||||||||||||||||||||||
if (isNotEnglish(value)) { | ||||||||||||||||||||||||||
throw new IllegalArgumentException("사람 이름은 영문자만 가능합니다. 현재 입력은 " + value + " 입니다."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private boolean isNotEnglish(final String value) { | ||||||||||||||||||||||||||
return !NAME_FORMAT.matcher(value).matches(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private void validateLength(final String value) { | ||||||||||||||||||||||||||
if (hasExceedLength(value)) { | ||||||||||||||||||||||||||
throw new IllegalArgumentException("사람 이름은 " + NAME_MAX_LENGTH + "글자까지 가능합니다. 현재 입력은 " + value + " 입니다."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
private boolean hasExceedLength(final String value) { | ||||||||||||||||||||||||||
return NAME_MAX_LENGTH < value.length(); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
public String getValue() { | ||||||||||||||||||||||||||
return value; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||
public boolean equals(final Object o) { | ||||||||||||||||||||||||||
if (this == o) { | ||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if (o == null || getClass() != o.getClass()) { | ||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
final Name name = (Name) o; | ||||||||||||||||||||||||||
return Objects.equals(getValue(), name.getValue()); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||
public int hashCode() { | ||||||||||||||||||||||||||
return Objects.hash(getValue()); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package ladder.domain; | ||
|
||
import java.util.Objects; | ||
|
||
public class Player { | ||
|
||
private final Name name; | ||
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. 위에서 인스턴스 변수를 value로 설정하셨는데, 여기선 name로 설정되어있네요. 전체 소프트웨에서 통일시켜주세요 :) "값 객체의 경우 값 그자체가 의미를 나타내기에 속성은 value로 통일한다." 라는 등의 다즐만의 기준이 있으면 좋겠어요. 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.
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. 네, 속성이 1개인 경우에는, Height, Name와 같이, 클래스가 해당 의미를 담고 있다고 생각해도 무방할 것 같습니다. 다른 2곳에서 속성값이 1개인 경우에 value로 설정했으니, Player도 value로 설정해도, 무방할 것 같고, 일관성도 지켜지는 것 같아서요. |
||
|
||
public Player(final String value) { | ||
this.name = new Name(value); | ||
} | ||
|
||
public String getName() { | ||
return name.getValue(); | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
final Player player = (Player) o; | ||
return Objects.equals(name, player.name); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(name); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package ladder.domain; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
public class Players { | ||
|
||
private static final int MINIMUM_PLAYER_SIZE = 2; | ||
private static final int MAXIMUM_PLAYER_SIZE = 10; | ||
|
||
private final List<Player> players; | ||
|
||
public Players(final List<String> names) { | ||
final List<Player> players = generatePlayers(names); | ||
validate(players); | ||
this.players = players; | ||
} | ||
|
||
private List<Player> generatePlayers(final List<String> names) { | ||
return names.stream() | ||
.map(Player::new) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private void validate(final List<Player> players) { | ||
validatePlayerSize(players); | ||
validateDuplicatePlayer(players); | ||
} | ||
|
||
private void validatePlayerSize(final List<Player> players) { | ||
if (hasSmallSize(players) || hasLargeSize(players)) { | ||
throw new IllegalArgumentException( | ||
"플레이어는 " + MINIMUM_PLAYER_SIZE + "명 이상, " + MAXIMUM_PLAYER_SIZE + "명 이하만 가능합니다." | ||
+ " 현재 입력한 플레이어 수는 " + players.size() + "명 입니다."); | ||
} | ||
} | ||
|
||
private boolean hasSmallSize(final List<Player> players) { | ||
return players.size() < MINIMUM_PLAYER_SIZE; | ||
} | ||
|
||
private boolean hasLargeSize(final List<Player> players) { | ||
return MAXIMUM_PLAYER_SIZE < players.size(); | ||
} | ||
|
||
private void validateDuplicatePlayer(final List<Player> players) { | ||
final Set<Player> uniquePlayers = new HashSet<>(players); | ||
|
||
if (isDuplicate(players, uniquePlayers)) { | ||
throw new IllegalArgumentException("플레이어 이름은 중복되면 안됩니다."); | ||
} | ||
} | ||
|
||
private boolean isDuplicate(final List<Player> players, final Set<Player> uniquePlayers) { | ||
return players.size() != uniquePlayers.size(); | ||
} | ||
|
||
public List<String> getPlayerNames() { | ||
return players.stream() | ||
.map(Player::getName) | ||
.collect(Collectors.toUnmodifiableList()); | ||
} | ||
|
||
public int size() { | ||
return players.size(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package ladder.domain.generator; | ||
|
||
import ladder.domain.Direction; | ||
|
||
@FunctionalInterface | ||
public interface DirectionGenerator { | ||
|
||
Direction generate(); | ||
} |
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.
오오.. 유비쿼터스 언어를 잘 정의해주셨네요
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.
해당 명세서를 개발자만 읽는 것이 아닌, 모두가 읽을 수 있게 만들기 위해 고민했던 것 같습니다 😀