질문, 피드백 등 모든 댓글 환영합니다.
건국대학교 교내 IT 동아리 KUIT에서 진행한 1~2주차 미션에 관한 내용입니다.
Back-end 학습에 앞서 자바의 핵심 요소인 객체지향에 익숙해지기 위해 소트웍스 엔솔로지의 객체지향 생활체조 원칙
을 준수하여 아래 요구사항에 맞춰 개발합니다.
Before
1* -1 0 0 0
0 1 -1 0 0
0 0 0 0 0
0 0 0 0 0
// 사다리의 1을 만났으니 왼쪽으로 이동한다.
After
1 -1* 0 0 0
0 1 -1 0 0
0 0 0 0 0
0 0 0 0 0
// 이동 후 아래로 한칸 내려간다.
Before
1 -1 0 0 0
0 1* -1 0 0
0 0 0 0 0
0 0 0 0 0
// 반복 ...
사다리 행*열 *0.3
LadderGame
에 인터페이스를 활용한 의존성 주입을 통해 LadderCreator
를 변경할 수 있도록 해본다. LadderGame ladderGame = LadderGameFactory.createRandomLadderGame()
전체 코드 : GitHub
사다리 게임의 시작 부분으로 사다리 번호를 입력하면 사다리게임을 진행하여 최종 사다리 번호를 반환.
private final LadderCreator ladderCreator;
public static LadderGame of(LadderCreator ladderCreator) {
return new LadderGame(ladderCreator);
}
public int run(LadderNumber ladderNum) {
CurrentPosition currentPosition = CurrentPosition.createCurrentPosition(ladderNum);
LadderRunner.of(ladderCreator.getLadder()).run(currentPosition);
return currentPosition.getY();
}
LadderGame 생성과 LadderCreator에 대한 의존성 주입 담당.
public class LadderGameFactory {
private LadderGameFactory() {}
public static LadderGame createSelfLadderGame(int row, int numberOfPerson) {
SelfLadderCreator selfLadderCreator = new SelfLadderCreator(
Ladder.of(NumberOfRow.of(row), NumberOfPerson.of(numberOfPerson)));
return LadderGame.of(selfLadderCreator);
}
public static LadderGame createRandomLadderGame(int row, int numberOfPerson) {
Ladder ladder = Ladder.of(NumberOfRow.of(row), NumberOfPerson.of(numberOfPerson));
SelfLadderCreator selfLadderCreator = new SelfLadderCreator(ladder);
RandomLadderCreator randomLadderCreator = new RandomLadderCreator(ladder, selfLadderCreator);
return LadderGame.of(randomLadderCreator);
}
}
사다리의 가로 선을 생성하는 역할.
public interface LadderCreator {
void drawLine(int x, int leftY, int rightY);
void drawLine();
Ladder getLadder();
}
public class SelfLadderCreator implements LadderCreator{
private final Ladder ladder;
public SelfLadderCreator(Ladder ladder) {
this.ladder = ladder;
}
@Override
public void drawLine(Rung rung) {
ladder.setLine(rung.getLeftPointXInt(),
rung.getLeftPointYInt(), rung.getRightPointYInt());
}
/**
* @deprecated
*/
@Override
public void drawLine() {
throw new UnsupportedOperationException();
}
...
public class RandomLadderCreator implements LadderCreator {
private final Ladder ladder;
private final LadderCreator selfLadderCreator;
public RandomLadderCreator(Ladder ladder, LadderCreator selfLadderCreator) {
this.ladder = ladder;
this.selfLadderCreator = selfLadderCreator;
drawLine();
}
/**
* @deprecated
*/
@Override
public void drawLine(int x, int leftY, int rightY) {
throw new UnsupportedOperationException();
}
@Override
public void drawLine() {
int count = (int) (ladder.getRowSize() * ladder.getNumberOfPersonSize() * 0.3);
Set<Rung> randomRungs = RandomRung.getRandomRungs(ladder, count);
randomRungs.forEach(rung -> selfLadderCreator.drawLine(rung));
}
...
사다리 생성 정책에 맞도록 랜덤한 위치를 가지는 Rung을 개수에 맞게 생성하여 반환.
public static Set<Rung> getRandomRungs(Ladder ladder, int count) {
Set<Rung> randomRungSet = new HashSet<>(count);
while (randomRungSet.size() != count){
randomRungSet.add(getRandomRung(ladder));
}
return randomRungSet;
}
private static Rung getRandomRung(Ladder ladder) {
int randomX = RandomUtil.generate(ladder.getRowSize());
int randomY = RandomUtil.generate(ladder.getNumberOfPersonSize() - 1);
return Rung.of(randomX, randomY, randomY + 1);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rung rung = (Rung) o;
return Objects.equals(leftPoint, rung.leftPoint) || Objects.equals(rightPoint, rung.rightPoint)
|| Objects.equals(rightPoint, rung.leftPoint) || Objects.equals(leftPoint, rung.rightPoint);
}
@Override
public int hashCode() {
return 1;
}
사다리 게임의 본격적인 시작이 진행되는 클래스.
private final Ladder ladder;
public void run(CurrentPosition currentPosition) {
LadderViewer ladderViewer = LadderViewer.of(ladder);
for (int i = 0; i < ladder.getRowSize(); i++) {
currentPosition.setX(i);
ladderViewer.view("BEFORE", currentPosition);
ladder.nextPosition(i, currentPosition);
ladderViewer.view("AFTER", currentPosition);
}
}
사다리게임의 현황을 출력.
public class LadderViewer {
private final CurrentPosition currentPosition;
private final Ladder ladder;
public void view(String message, CurrentPosition currentPosition) {
System.out.println(message);
ladder.view(currentPosition);
System.out.println();
}
}
2차원 배열을 기반으로 사다리를 구성.
private final Row[] rows;
private Ladder(NumberOfRow row, NumberOfPerson numberOfPerson) {
rows = new Row[row.getNumberOfRow()];
for (int i = 0; i < row.getNumberOfRow(); i++) {
rows[i] = new Row(numberOfPerson);
}
}
public static Ladder of(NumberOfRow row, NumberOfPerson numberOfPerson) {
return new Ladder(row, numberOfPerson);
}
public void nextPosition(int i, CurrentPosition currentPosition) {
rows[i].nextPosition(currentPosition);
}
public void view(CurrentPosition currentPosition) {
for (int i = 0; i < getRowSize(); i++) {
rows[i].viewValues(i, currentPosition);
}
}
public void setLine(int x, int leftY, int rightY) {
rows[x].setValue(leftY, rightY);
}
사다리 도메인에서 하나의 행을 관리.
public class Row {
private Node[] nodes;
public Row(NumberOfPerson numberOfPerson) {
this.nodes = new Node[numberOfPerson.getNumberOfPerson()];
for (int i = 0; i < numberOfPerson.getNumberOfPerson(); i++) {
nodes[i] = Node.createCenterNode();
}
}
public void nextPosition(CurrentPosition currentPosition) {
validateCurrentPositionY(currentPosition);
if (nodes[currentPosition.getY()].isLeft()) {
currentPosition.goRight();
return;
}
if (nodes[currentPosition.getY()].isRight()) {
currentPosition.goLeft();
return;
}
}
...
public void viewValues(int row, CurrentPosition currentPosition) {
for (int i = 0; i < nodes.length; i++) {
if (currentPosition.equal(row, i)) {
System.out.print(getValue(i) + "* ");
continue;
}
System.out.print(getValue(i) + " ");
}
System.out.println();
}
public class Node {
private Direction direction;
public int getValue() {
return direction.getDirection();
}
public boolean isLeft() {
return direction.equals(Direction.LEFT);
}
public boolean isRight() {
return direction.equals(Direction.RIGHT);
}
}
해당 예제에서는 정적 팩토리 패턴을 통한 DI를 설명하고 구현하기 위해서 LadderCreator를 인터페이스로 정의 후 LadderGameFactory를 통해 의존성을 주입해주는 방식의 요구사항이 있었습니다.
DI를 예제에 녹여내기 위해 이런 요구사항이 주어진 것은 이해하지만 한가지 의구심이 남습니다.