DevLog ๐ถ
[์ฐํ ์ฝ 5๊ธฐ] ์ฒด์ค ๊ฒ์ ๊ตฌํ ๋ฏธ์ ํ๊ณ ๋ณธ๋ฌธ
[์ฐํ ์ฝ 5๊ธฐ] ์ฒด์ค ๊ฒ์ ๊ตฌํ ๋ฏธ์ ํ๊ณ
dolmeng2 2023. 4. 5. 22:27์ ๋๋ ํจ๊ปํ ๋ค ๋ฒ์งธ ํ์ด ํ๋ก๊ทธ๋๋ฐ์ด๋ค.
๋ฏธ์ ์ ์งํํ ๋น์์๋ ๋์ด๋๊ฐ ํ ๋ด ๋๋์ด๋ผ ์ด๋ ต๋ค๋ ์๊ฐ, ๊ทธ๋ฆฌ๊ณ ์๊ฐ์ด ๋๋ฌด ์ด๋ฐํ๋ค๋ ์๊ฐ๋ฟ์ด์๋๋ฐ ๋ค ๋๋๊ณ ๋์ ๋์๋ณด๋๊น ๋๋ฆ๋๋ก ์ ํด๋ธ ๊ฒ ๊ฐ๋ค. (๋ฌผ๋ก ... ์ฝ๋๊ฐ ๋ง์์ ๋ ๋ค๋ ๋ง์ ์๋๋ค ๐ฅน ์ ๋ง ๋ง์ด ๋ถ์กฑํ๋ค...)
๊ทธ๋๋ ๋ ๋ฒจ 1 ๋ง์ง๋ง ๋ฏธ์ ๊น์ง ์ด๋ป๊ฒ๋ ์จ ๋ด ์์ ์ด ๋๊ฒฌํ๋ค! ์์ผ๋ก๋ ํ๋ด์ ๐ช
โ๏ธ ์์ฑํ ์ฝ๋
โ๏ธ 1์ฐจ PR
โ๏ธ 2์ฐจ PR
โ๏ธ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ
[1๋จ๊ณ]
์ฝ์ UI์์ ์ฒด์ค ๊ฒ์์ ํ ์ ์๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
1๋จ๊ณ๋ ์ฒด์ค ๊ฒ์์ ํ ์ ์๋ ์ฒด์คํ์ ์ด๊ธฐํํ๋ค.
์ฒด์คํ์์ ๋ง์ ์์น ๊ฐ์ ๊ฐ๋ก ์์น๋ ์ผ์ชฝ๋ถํฐ a ~ h์ด๊ณ , ์ธ๋ก๋ ์๋๋ถํฐ ์๋ก 1 ~ 8๋ก ๊ตฌํํ๋ค.
์ฒด์คํ์์ ๊ฐ ์ง์์ ๊ฒ์์(๋๋ฌธ์)๊ณผ ํฐ์(์๋ฌธ์) ํธ์ผ๋ก ๊ตฌ๋ถํ๋ค.
[2๋จ๊ณ]
์ฒด์ค ๋ง์ ์ด๋ ๊ท์น์ ์ฐพ์๋ณด๊ณ ์ฒด์ค ๋ง์ด ์ด๋ํ ์ ์๋๋ก ๊ตฌํํ๋ค.
move source์์น target์์น์ ์คํํด ์ด๋ํ๋ค.
์ฒด์คํ์ ์์น ๊ฐ์ ๊ฐ๋ก ์์น๋ ์ผ์ชฝ๋ถํฐ a ~ h์ด๊ณ , ์ธ๋ก๋ ์๋๋ถํฐ ์๋ก 1 ~ 8๋ก ๊ตฌํํ๋ค
[3๋จ๊ณ]
์ฒด์ค ๊ฒ์์ ์๋ํธ King์ด ์กํ๋ ๊ฒฝ์ฐ ๊ฒ์์์ ์ง๋ค. King์ด ์กํ์ ๋ ๊ฒ์์ ์ข
๋ฃํด์ผ ํ๋ค.
์ฒด์ค ๊ฒ์์ ํ์ฌ ๋จ์ ์๋ ๋ง์ ๋ํ ์ ์๋ฅผ ๊ตฌํ ์ ์์ด์ผ ํ๋ค.
"status" ๋ช
๋ น์ ์
๋ ฅํ๋ฉด ๊ฐ ์ง์์ ์ ์๋ฅผ ์ถ๋ ฅํ๊ณ ์ด๋ ์ง์์ด ์ด๊ฒผ๋์ง ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์์ด์ผ ํ๋ค.
- ์ ์ ๊ณ์ฐ ๊ท์น-
์ฒด์ค ํ๋ก๊ทธ๋จ์์ ํ์ฌ๊น์ง ๋จ์ ์๋ ๋ง์ ๋ฐ๋ผ ์ ์๋ฅผ ๊ณ์ฐํ ์ ์์ด์ผ ํ๋ค.
๊ฐ ๋ง์ ์ ์๋ queen์ 9์ , rook์ 5์ , bishop์ 3์ , knight๋ 2.5์ ์ด๋ค.
pawn์ ๊ธฐ๋ณธ ์ ์๋ 1์ ์ด๋ค. ํ์ง๋ง ๊ฐ์ ์ธ๋ก์ค์ ๊ฐ์ ์์ ํฐ์ด ์๋ ๊ฒฝ์ฐ 1์ ์ด ์๋ 0.5์ ์ ์ค๋ค.
king์ ์กํ๋ ๊ฒฝ์ฐ ๊ฒฝ๊ธฐ๊ฐ ๋๋๊ธฐ ๋๋ฌธ์ ์ ์๊ฐ ์๋ค.
ํ ๋ฒ์ ํ ์ชฝ์ ์ ์๋ง์ ๊ณ์ฐํด์ผ ํ๋ค.
[4๋จ๊ณ]
์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ์์ํ๋๋ผ๋ ์ด์ ์ ํ๋ ์ฒด์ค ๊ฒ์์ ๋ค์ ์์ํ ์ ์์ด์ผ ํ๋ค.
DB๋ฅผ ์ ์ฉํ ๋ ๋๋ฉ์ธ ๊ฐ์ฒด์ ๋ณ๊ฒฝ์ ์ต์ํํด์ผํ๋ค.
๋ฏธ์ ์ ์งํํ๋ฉด์ ์ธ์ ๊น์๋ ๋ถ๋ถ์ ๋ํด ์์ฑํด๋ณด๊ณ ์ ํ๋ค ๐ซ
๐ฌ ๋๋ฉ์ธ๊ณผ ๋ทฐ์ ์์กด์ ์ด๋ ์ ๋๋ก ๋์ด์ผ ํ๋๊ฐ?
์ฌ์ค ์๋์ฐจ ๋ฏธ์ ๋ ๋๋ฉ์ธ์ด ๋ทฐ๋ฅผ ์์กดํด์๋ ์ ๋๋ ์ด์ ์ ๋ํด ๊ณ ๋ฏผํ๊ธฐ ๋๋ฌธ์, ๋น์ฐํ๊ฒ๋ ๋๋ฉ์ธ์ ๋ทฐ๋ฅผ ์๋ฉด ์ ๋๋ค๊ณ ์๊ฐํ๋ค. ํ์ง๋ง, ๋ทฐ ์ญ์ ๋๋ฉ์ธ์ ์๋ ๊ฒ์ ๋ํด์๋ ๊ณ ๋ คํ์ง ์์๋ค. ์ด์ฐจํผ ๋ทฐ๋ ๋๋ฉ์ธ ์์ญ์ ๋ํ ์์์ ์ถ๋ ฅํด์ฃผ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์์กดํด๋ ์๊ด์๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ด๋ค... ๐ฅฒ ๋น์ฐํ๊ฒ๋ ์ด ๋ถ๋ถ์ ๋ํ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ๊ฒ ๋์๋ค.
public enum PieceName {
QUEEN(PieceType.QUEEN, 'Q'),
ROOK(PieceType.ROOK, 'R'),
KNIGHT(PieceType.KNIGHT, 'N'),
PAWN(PieceType.PAWN, 'P'),
BISHOP(PieceType.BISHOP, 'B'),
KING(PieceType.KING, 'K');
}
๋ฌธ์ ๊ฐ ๋์๋ ์ฝ๋์ด๋ค. pieceName์ ๊ฐ ๊ธฐ๋ฌผ๋ค์ ์ถ๋ ฅํ๊ธฐ ์ํ ๋ฉ์์ง๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ฌ๊ธฐ์ PieceType์ ๋๋ฉ์ธ ์์ญ์ enum์ด๊ธฐ ๋๋ฌธ์ view ํจํค์ง ๋ด๋ถ์ ์๋ PieceNamer๊ณผ ๋๋ฉ์ธ ์์ญ์ PieceType์ ๊ฒฐํฉ๋๊ฐ ์ฆ๊ฐํ๋ ๊ฒ์ด๋ค.
์ฌ์ค ์ฒ์ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ์์ ๋๋, ๋ทฐ๊ฐ ๋๋ฉ์ธ์ ์์กดํด์๋ ์ ๋๋ ์ด์ ์ ๋ํด ์ ์ดํดํ์ง ๋ชปํ์๋ค.
๋ฆฌ๋ทฐ์ด๋์ ์ด์ ๋ํด์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํด์ฃผ์ จ๋ค.
- ๋ทฐ๊ฐ ๋๋ฉ์ธ์ ์์กดํ๊ฒ ๋๋ฉด ๋๋ฉ์ธ์ ์์ ๋กญ๊ฒ ๋ณ๊ฒฝํ ์๋ ์๊ฒ ๋๊ณ , view๋ ๋ณ๊ฒฝ์ด ์ฆ์๋ฐ ๋๋ฉ์ธ์ ์ฝ์ดํ ์์ญ์ด๋ผ ์ฌ๋ฌ ๊ณณ์์ ์ฐ๊ฒ ๋๋๋ฐ ๋ง์ ๊ณณ์ด ์ํฅ๋ฐ๊ฒ ๋ฉ๋๋ค.
- ๋น์ง๋์ค ์๊ตฌ์ฌํญ์ ๋ณ๊ฒฝ์ผ๋ก ๋๋ฉ์ธ์ด ๋ณ๊ฒฝ๋ ๋, api ๋ ๋ถํ์ํ๊ฒ ๋ณ๊ฒฝ๋์ผํ๋ ์ํฉ๋ ์๊น๋๋ค.
- ํ์ํธํ์ฑ์ผ๋ก ์ฌ์ฉ์๊ฐ ๋ฒ์ ์ ๋ฐ์ดํธ๋ฅผ ํ์ง ์๋ ์ด์ ์ธ๋ถ๋ก ๋๊ฐ๋ฒ๋ฆฐ ๋๋ฉ์ธํ๋๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ ์๋ ์์ด์.
์์ง ๋ ๋ฒจ 1 ๋จ๊ณ์์๋ ๊ฒช๊ธฐ ์ด๋ ค์ด ๋ฌธ์ ์ง๋ง... ์ฌ๋ฌ๋ชจ๋ก ์๊ฐ์ ํด๋ณด์๋ค.
๋ง์ฝ ํ์ฌ ์๊ตฌ์ฌํญ์์ 'ํน๋ณํ ์ฒด์ค๊ฒ์'์ ๋ง๋ค๋ผ๋ ๊ฒ ์๊ตฌ์ฌํญ์ด ๋์ด์, ๋๋ฉ์ธ์ PieceType์ด ์์ ๋ฌ๋ผ์ง๊ฒ ๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น? view ์์ญ ์ญ์ ํจ๊ป ์์ ๋ ์๋ฐ์ ์๋ค. ํ์ง๋ง, ๋ง์ฝ ์ง๊ธ ๋ฒ์ ์ด ๋ฐฐํฌ๊ฐ ๋์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์ด๋ฏธ ์ธ๋ถ๋ก ๋ฐฐํฌ๊ฐ ๋๊ฐ ์ด์, ํด๋น ํ๋๋ ์ฌ์ฉ์์ ์ ๋ฐ์ดํธ์ ๋ฌ๋ฆฌ๊ฒ ๋๋ค. ์ฌ์ฉ์์๊ฒ ๊ฐ์ ๋ก ๋ฒ์ ์ ๋ฐ์ดํธ๋ฅผ ์ํค๊ธฐ ์ ๊น์ง ํด๋น ๋๋ฉ์ธ์ ์์ ์ด ๋ถ๊ฐ๋ฅํ ์ํ๊ฐ ๋๋ ๊ฒ์ด๋ค. (๊ทธ๋์ ๋ณดํต ์ ํ๋ฆฌ์ผ์ด์ ๋ค์ด ๋ฒ๊ทธ ์ฌํญ์ ๋ํด ๊ฐ์ ์ ๋ฐ์ดํธ๋ฅผ ์งํํ๋ ๊ฑด๊ฐ ์ถ๊ธฐ๋ ํ๊ณ ...)
๋ฐ๋ฉด์, view์ ๋ํด์ ์์ ํ ์์กด์ฑ์ ๋์ด์ฃผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ๋๋ฉ์ธ์ ๋ํ ๊ธฐ๋ฅ์ด ๋ณ๊ฒฝ๋๋๋ผ๋ ๋ทฐ์๋ ์ํฅ์ ๋ฏธ์น์ง ์๊ฒ ๋๋ค. ์๋๋ ํผ๋๋ฐฑ์ ๋ฐ์ ์์ ํ ์ฝ๋์ด๋ค.
public enum PieceName {
QUEEN("QUEEN", 'Q'),
ROOK("ROOK", 'R'),
KNIGHT("KNIGHT", 'N'),
PAWN("PAWN", 'P'),
BISHOP("BISHOP", 'B'),
KING("KING", 'K');
}
๊ฐ์ String์ผ๋ก ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋ฉ์ธ์ด ๋ณ๊ฒฝ๋๋๋ผ๋ ์ฐ์ ๋ฐฐํฌ๊ฐ ๋๊ฐ ๋ถ๋ถ์ ๋ํด์๋ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. (์ด๋ ํ ๋๋ฉ์ธ๊ณผ๋ ์์กด์ ๋งบ์ง ์๊ณ ์๋ ์ํ) ๋ฌผ๋ก , ์ํ๋๋๋ก ๋์์ํค๊ธฐ ์ํด์๋ ๋น์ฐํ ๋ฐฐํฌ์ ๋ํ ์์ ๋ณธ์ ๋ฐ์์ผ ํ์ง๋ง, ์๋ก์ด ๋๋ฉ์ธ์ด ์ถ๊ฐ๋์์ ๋ ์กฐ๊ธ ๋ ์ ์ฐํ๊ฒ ๋์ํ ์ ์๊ฒ ๋๋ ๊ฒ์ด๋ค.
๋ด ๋๋ฆ๋๋ก ์ ์ํ ๋ถ๋ถ์ด๊ธฐ ๋๋ฌธ์ ์ณ์์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง, ๋ฆฌ๋ทฐ์ด๋์ ๋ ๋ฒจ์ด ์ฌ๋ผ๊ฐ๋ฉด ์์ฐ์ค๋ฝ๊ฒ ์๊ฒ ๋ ๋ด์ฉ์ด๋ผ๊ณ ํ์ จ๋ค.
๋๋ ์์์ ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ ๋ ๋๋ฉ์ธ๊ณผ ๋ทฐ ์ฌ์ด์ ์ํธ ์ฐธ์กฐ๋ฅผ ์ค์ผ ์ ์๋๋ก ๋ง๋ค์ด์ผ๊ฒ ๋ค.
๐ฌ ํฐ์ ์์ง์์ ๋ํ์ฌ
์๋ง ๋ง์ ํฌ๋ฃจ๋ค์ด ์ด ๋ถ๋ถ์ ๋ํด์ ์ด๋ ค์ํ์ ๊ฒ ๊ฐ๋ค. ๋ ์ญ์๋ ํฐ์ ์์ง์ ๋๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ณ๊ฒฝํ๋ค.
์ฒ์์๋ 'Piece'๋ผ๋ ํด๋์ค์ ๋ํด์ ๋ชจ๋ ๊ธฐ๋ฌผ๋ค์ด ํด๋น ๊ธฐ๋ฌผ์ ์์๋ฐ๋๋ก ์งํํ๋ค. (Piece๋ ์ถ์ ํด๋์ค)
๋๋ต ์ด๋ฐ ๊ตฌ์กฐ์๋ค. ํ์ง๋ง ๋ฑ ๋ด๋ ์ด์ํ๋ค. ๊ฐ ๊ธฐ๋ฌผ๋ค์ด ๋ด๋ถ ์ ์ ํ๋๋ก Move์ ๊ตฌํ์ฒด์ ๋ํด ๊ฐ์ง๊ณ ์์๋ ๊ฒ์ด๋ค.
public class Rook extends Piece {
private final RookMove rookMove = new RookMove();
public Rook(final PieceType pieceType, final CampType campType) {
super(pieceType, campType);
}
@Override
public boolean canMove(final Position source, final Position target) {
return rookMove.canMove(source, target);
}
@Override
public boolean canAttack(final Position source, final Position target) {
return rookMove.canAttack(source, target);
}
@Override
public boolean isPossibleRoute(final Position source, final Position target, final boolean isPossible) {
return rookMove.isPossibleRoute(source, target, isPossible);
}
}
์ด๋ฐ ๊ตฌ์กฐ๋ก ๋ชจ๋ ๋ง๋ค์ด ์ด๋ฃจ์ด์ ธ ์์ผ๋ฉฐ, ๊ธฐ๋ฌผ์ ์์ง์์ ๋ํด์ bypass๋ฅผ ํ๋ ๋ฐฉ์์ด์์ด์ ์๋ฏธ์๋ ๊ฐ์ฒด์๋ค.
์ฌ์ค ์ด๋ฒ ๋ฏธ์ ์์๋ ์ธ์คํด์ค ํ๋์ ๊ฐ์๋ฅผ 2๊ฐ ์ดํ๋ก ์ค์ด๋ ค๋ค๋ณด๋๊น ์ด๋ฐ ์ฌ๋จ์ด ๋ฌ๋ค... ๐ฆ
new Rook(PieceType.ROOK, campType);
์ธ๋ถ์์๋ ์ด๋ฐ ์์ผ๋ก ์ด๊ธฐํ๋ฅผ ํ์๋ค.
ํ์ง๋ง, PieceType์ด๋ผ๋ enum์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ฐ ๊ธฐ๋ฌผ์ ๋ํ ํ์ ์ ๋ณด๊ฐ ์ด๋ฏธ ์๊ณ , ์ ์ ๋ณ์๋ก Move๋ฅผ ์ด๊ธฐํํด์ฃผ๋ ๊ฒ์ ๋คํ์ฑ ์ธก๋ฉด์์๋ ๊ฒฐํฉ๋๊ฐ ๋๋ฌด ์ฆ๊ฐํ๊ธฐ ๋๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์์ ํ ๋ณ๊ฒฝํ์๋ค.
์ธ์คํด์ค ํ๋์ ๊ฐ์ ์ ํ์ ํฌ๊ธฐํ๊ณ , ์ธ๋ถ์์ ๊ธฐ๋ฌผ์ ์์ฑํ ๋ PieceType๊ณผ Movable (๊ธฐ์กด์ Move, ์ธํฐํ์ด์ค์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ -able๊ณผ ๊ฐ์ ํํ๋ก ๋ง๋ค์๋ค.)์ ์ฃผ์ ํ๋ ์์ผ๋ก ์งํํ์๋ค.
๋ํ, Piece๋ฅผ ์ถ์ ํด๋์ค๋ก ์ ์ธํ์ง ์๊ณ ์ผ๋ฐ ํด๋์ค๋ก ์ ํํ์์ผ๋ฉฐ, ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ๊ธฐ๋ฌผ์ ๋ํด 'Piece'๋ผ๋ ํด๋์ค๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์ด์ ๋ณด๋ค ์๋ง์ ์ถ์ํ ๋ ๋ฒจ์ ๊ฐ์ง๊ฒ ๋๋ค.
๋ํ, ๊ตฌ์กฐ๋ฅผ ๋ฐ๊พธ๋ฉด์ ์ธ๋ถ์์ pawn์ ๋ํด ์ฒดํฌํ ํ์๊ฐ ์์ด์ก๋ค.
์ด์ ์๋ 'ChessGame'์ด๋ผ๋ ๊ฐ์ฒด์์ ์์ง์์ ์งํํ ๋ pawn์ ์์ง์์ ๋ํด์ ๋ณ๋์ ๋ก์ง์ ์คํํ์๋ค.
// source -> target์ผ๋ก ์ฒด์ค๋ง์ ์ด๋์ํค๋ ๋ฉ์๋.
private void play(final Position source, final Position target) {
final Piece piece = chessBoard.checkPiece(source);
validateCamp(piece);
validateTargetSameCamp(target);
validateObstacle(source, target, piece);
if (validateAttack(source, target, piece)) {
return;
}
if (checkPawnMove(source, target, piece)) {
return;
}
movePiece(source, target, piece);
}
private boolean checkPawnMove(final Position source, final Position target, final Piece piece) {
if (piece.isPawn() && piece.canMove(source, target)) {
validatePawnMove(source, target, piece);
return true;
}
return false;
}
private void validatePawnMove(final Position source, final Position target, final Piece piece) {
if ((piece.isSameCamp(CampType.WHITE) && source.isRankSame(WHITE_PAWN_FIRST_MOVE)) ||
(piece.isSameCamp(CampType.BLACK) && source.isRankSame(BLACK_PAWN_FIRST_MOVE))) {
movePiece(source, target, piece);
return;
}
if (Math.abs(target.calculateRankGap(source)) != PAWN_FIRST_MOVE) {
throw new IllegalArgumentException("ํฐ์ ์ฒ์ ์ดํ 1์นธ๋ง ์ ์งํ ์ ์์ต๋๋ค.");
}
movePiece(source, target, piece);
}
๊ธฐ์กด์ ์์ฑํ๋ ์ฝ๋์ด๋ค. ์ง๊ธ ๋ด๋ ์ ์ด๋ ๊ฒ ์ง ๊ฑธ๊น ์ถ๊ธฐ๋ ํ์ผ๋...
ํฐ์ ์ด๋์ ๊ฒฝ์ฐ ๋๊ฐ์ ์์ ์๋ ์์น์ ๋ํด์๋ง ๊ณต๊ฒฉ์ด ๊ฐ๋ฅํ๋ฉฐ, ์ด๋ฅผ ํ๋จํ๊ธฐ ์ํด์๋ ๋ณด๋์ ๋ํ ์ ๋ณด๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ chessGame์์ ์ด๋ฅผ ํ๋จํ๋๋ก ์งํํ์๋ค. (๋ํ, ํ์ฌ ํ๋ ์ดํ๊ณ ์๋ ์ง์์ ๋ํ ์ ๋ณด๋ ํ์ํ๋ ์ํ)
๊ธฐ์กด์๋ canMove, canAttack๊ฐ ๋จ์ํ ์์ํ๋ ๋ฉ์๋๋ค ๋ณด๋๊น ์ด๋ฐ ์์ผ๋ก ์งํํ์๋ ๊ฒ ๊ฐ๋ค.
public void play(final Position source, final Position target) {
validateCamp(source);
validateTargetSameCamp(target);
validateObstacle(source, target);
if (!canAttack(source, target) && !canMove(source, target)) {
throw new IllegalArgumentException("์ด๋ํ ์ ์๋ ์์น์
๋๋ค.");
}
movePiece(source, target);
currentCamp = currentCamp.changeTurn();
}
private boolean canAttack(final Position source, final Position target) {
final Piece sourcePiece = chessBoard.getPiece(source);
final boolean isTargetExist = chessBoard.contains(target);
return sourcePiece.canAttack(source, target, isTargetExist);
}
private boolean canMove(final Position source, final Position target) {
final Piece piece = chessBoard.getPiece(source);
boolean isTargetExist = chessBoard.contains(target);
return piece.canMove(source, target, isTargetExist);
}
ํ์ง๋ง, ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ๋ฉด์ ์์ ๊ฐ์ด pawn์ด๋ผ๋ ์กฐ๊ฑด์ ์ธ๋ถ์์ ํ๋จํ ํ์๊ฐ ์์ด์ก๋ค.
piece์์ pieceType์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ฌผ์๊ฒ ๋ณธ์ธ์ด ํฐ์ธ์ง ๋ฌผ์ด๋ณผ ์ ์๊ฒ ๋์๊ณ , ์ด๋ฅผ ํตํด ํฐ์ ํน๋ณํ ์์ง์์ ๋ํ ์กฐ๊ฑด์ ์ถ๊ฐํด์ค ์ ์๊ธฐ ๋๋ฌธ์ ์ธ๋ถ์์๋ ๊ธฐ๋ฌผ์ด ์์ง์ด๊ธฐ ์ํด ์ด๋ค ์กฐ๊ฑด์ด ํ์ํ์ง ์ ํ์๊ฐ ์๊ฒ ๋์๋ค.
๋ฌผ๋ก , ์ธ์๋ก isTargetExist๋ฅผ ํตํด ๋์ฐฉ ์ง์ ์ ๊ธฐ๋ฌผ์ด ์๋์ง๋ฅผ ์ฒดํฌํ๋ ๋ณ์๊ฐ ๋ค์ด๊ฐ์ง๋ง, ๋ก์ง ์์ฒด๊ฐ ์ธ๋ถ์ ์๋ ๊ฒ๋ณด๋ค๋ ๊ธฐ๋ฌผ ์์ฒด๊ฐ ์ธ์๋ก ๋ฐ์ ๊ฐ๋ค์ ๋ฐํ์ผ๋ก ๋ณธ์ธ์ด ์์ง์ผ ์ ์๋์ง ํ๋จํ๋ ํ ๊ตฌ์กฐ๊ฐ ๋ ๋ซ๋ค๊ณ ์๊ฐํ๋ค.
// Piece.java
public boolean canMove(final Position source, final Position target, final boolean isTargetExist) {
if (pieceType == PieceType.PAWN && movable.canMove(source, target)) {
validatePawnDirection(source, target);
return validatePawnMove(source, target, isTargetExist);
}
return movable.canMove(source, target);
}
public boolean canAttack(final Position source, final Position target, final boolean isTargetExist) {
if (pieceType == PieceType.PAWN) {
validatePawnDirection(source, target);
validatePawnCanAttack(source, target, isTargetExist);
}
return movable.canAttack(source, target);
}โ
Piece์์ ์ ์ธํ ๋ฉ์๋์ด๋ค. ์์ ๊ฐ์ด ํฐ์ธ ๊ฒฝ์ฐ ๊ฒ์ฆ ์กฐ๊ฑด์ ์ถ๊ฐํ์ฌ์ ํฐ์ด ์์ง์ผ ์ ์๋ ์กฐ๊ฑด์ ๋ํด์ ์ฒดํฌํ์๋ค.
์ฝ๋๋ก ์์ฑํ๊ณ ๋๋๊น ๋ณ๊ฒฝ์ด ์๋ ๊ฒ ๊ฐ์ง๋ง... ์ด ๊ตฌ์กฐ๊น์ง ์ค๋ ๊ฒ ์๋นํ ํ๋ค์๋ค ๐ฅฒ
๋ฌผ๋ก ๋ ์ข์ ๊ตฌ์กฐ๊ฐ ์์ ๊ฒ ๊ฐ์ง๋ง, ํ ๊ตฌ์กฐ์์๋ ์ด๋ ๊ฒ ๋ง๋๋ ๊ฒ์ด ์ต์ ์ด ์๋๊น ์ถ๋ค...
๐ฌ ์ปค๋งจ๋ ํจํด ์ ์ฉํ๊ธฐ
์ด๋ฒ ๋ฏธ์ ์์ ์ ์ฉํ ์๋ก์ด ๋์์ธ ํจํด์ด๋ค. ์ฌ์ค ์ด ๋ถ๋ถ์ ๋ค๋ฅธ ํฌ๋ฃจ๋ค์ด ์ ์ฉํ ๊ฒ์ ๋ณด๊ณ ๋์ ํด๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ์ ์ ์ฉํ์๋ค.
start, status, move, end, ์ด 4๊ฐ์ง ๊ฒฝ์ฐ์ ๋ํด ์ฌ์ฉ์์๊ฒ ์ ๋ ฅ์ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๊ฐ์ ํ๋์ ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๊ธฐ์๋ ๋ถ๊ธฐ๋ฌธ์ด ๊ต์ฅํ ๋ง์์ง ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๋์๋ค.
์ด ๊ตฌ์กฐ์ ์ฅ์ ์ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ฐ๋ณ๊ฒ ๊ฐ์ ธ๊ฐ ์ ์๋ค๋ ์ ์ด๋ค.
(๋ ๊ฐ์ ๊ฒฝ์ฐ๋ ๊ฐ๊ฐ์ ์ํ๋ฅผ xxxController๋ผ๋ ์ด๋ฆ์ผ๋ก ์ง์๊ธฐ ๋๋ฌธ์, ๋ฉ์ธ์ผ๋ก ์งํํ๋ ์ปจํธ๋กค๋ฌ์ ์ด๋ฆ์ ChessHandler๋ก ์ง์๋ค. ๊ฐ๊ฐ์ ์ปจํธ๋กค๋ฌ๋ฅผ ์ ํํ๋ค๋ ์๋ฏธ๋ก ํธ๋ค๋ฌ๋ก ์ง์ ๊ฑด๋ฐ ๋ฆฌ๋ทฐ์ด๋์ด ์ถ์ฒํด์ฃผ์ จ๋ค.)
// ChessHandler.java
public void run() {
final long userId = getUserId();
OutputView.printStartMessage();
Controller controller = new StartController(chessGameService);
while (controller.isRun()) {
controller = play(controller, userId);
}
}
private Controller play(Controller controller, final long userId) {
try {
final List<String> commands = InputView.getCommands();
final Command command = Command.findCommand(commands);
controller = controller.checkCommand(command, userId);
final Optional<ChessGame> chessGame = controller.findGame(userId);
chessGame.ifPresent(game ->
OutputView.printBoard(ChessBoardDtoMapper.createChessBoardDto(game.getChessBoard())));
return controller;
} catch (IllegalArgumentException e) {
OutputView.print(e.getMessage());
return play(controller, userId);
}
}
์ต์ข ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๋ค ๋ณด๋๊น userId๋ ๊ทธ๋ฐ ๊ฒ๋ค์ด ๋ณด์ด์ง๋ง...
์ค์ํ ๋ถ๋ถ์ controller.isRun()์ ํตํด์ ๊ฒ์์ ์งํ ์ํ์ ๋ํด์ ์ฒดํฌํ๊ณ , ๊ณตํต์ ์ผ๋ก ์งํํด์ผ ํ๋ ์ฌ์ฉ์์ ์ปค๋ฉ๋ ์ฒดํฌ (checkCommand)๋ findGame (์งํ ์ค์ธ ์ฒด์ค ๊ฒ์์ ์ฐพ๋ ๋ถ๋ถ์ธ๋ฐ, ๋จ๊ณ๊ฐ ์ถ๊ฐ๋๋ฉฐ ๋ง๋ ๋ฉ์๋์ด๋ค ใ ใ ) ๋ฑ์ ๊ณตํต์ ์ผ๋ก ํธ์ถํ ์ ์๊ฒ ๋๋ค.
@Override
public Controller checkCommand(final Command command) {
if (command.isStart()) {
throw new IllegalArgumentException("์ด๋ฏธ ์์์ด ์๋ฃ๋์์ต๋๋ค.");
}
if (command.isEnd()) {
return new EndController();
}
if (command.isStatus()) {
return new StatusController(userId, chessGameService).getStatus(true);
}
return move(command);
}
๋ํ, ๊ฐ๊ฐ์ ์ปจํธ๋กค๋ฌ๋ค์ ์ฌ์ฉ์๊ฐ ์๋ชป๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ์๊ฑฐ๋, ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๋ช ๋ น์ด์ ๋ฐ๋ผ์ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๊ฒ ๋๋ค.
์ ์ฝ๋๋ MoveController์ด๋ฉฐ, ๋ง์ฝ move ์ํ์์ ์ฌ์ฉ์๊ฐ start๋ฅผ ์ ๋ ฅํ๋ฉด ์ค๋ฅ ๋ฉ์์ง๋ฅผ, end๋ฅผ ์ ๋ ฅํ๋ฉด ์ข ๋ฃํ๋๋ก ์ ์ด๋ฅผ, status๋ฅผ ์ ๋ ฅํ๋ฉด ํต๊ณ ์ ๋ณด๋ฅผ, ๊ทธ๊ฒ ์๋๋ผ๋ฉด ์์ง์์ ๋ํ ๋ก์ง์ ์คํํ๋๋ก ์ ์ดํ์๋ค.
์ฌ์ค ์ปค๋งจ๋ ํจํด์ ๊ฒฝ์ฐ ํฌ๋ฃจ๋ค ์ฌ์ด์์๋ ๋์ ์ ๋ํด์ ๋ง์ด ๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ด๋ค.
์คํ๋ ค ์ด๋ฐ ์์ผ๋ก ์์ธ๋ฅผ ํฐํธ๋ฆฌ๊ฑฐ๋ ๋ถ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ์งํํ๋ ๊ฒ ๋ถํ์ํ๋ค๋ ์๊ฒฌ๋ ์๊ณ , ํ ๊ตฌ์กฐ์์ผ๋ก๋ ์ํ๊ฐ ๊ทธ๋ ๊ฒ ๋ง์ง ์๊ธฐ ๋๋ฌธ์ ํ๋์ ์ปจํธ๋กค๋ฌ์์๋ ์ถฉ๋ถํ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ด๋ค.
๋ ์ญ์๋ start -> move๋ก ์์ํ๊ธฐ ์ํด์ ์ธ์คํด์ค ํ๋๋ฅผ ๊ณต์ ํ๋ ๋ฑ, ๋ถํ์ํ ์ฝ๋๊ฐ ๋ค์ด๊ฐ๋ค ๋ณด๋ ๋นผ๋ ๊ฒ์ ๋ํด์๋ ๊ณ ๋ฏผ์ ํ์๋ค. (๋ฌผ๋ก , ์ด๊ฒ๋ณด๋ค ๋ถ๊ธฐ ์ฒ๋ฆฌ๊ฐ ๋ ํ๋ค ๊ฒ ๊ฐ์์ ์ปค๋งจ๋ ํจํด์ ์ ์งํ์์ง๋ง...ใ ใ )
์ทจํฅ์ ๋ฐ๋ผ ๊ฐ๋ฆฌ๋ ๋ฌธ์ ์ด๊ธฐ ๋๋ฌธ์, ํน์ฌ๋ ๋์ ํ๊ฒ ๋ค๋ฉด ์ ๊ณ ๋ คํด๋ณด๊ณ ์ฌ์ฉํ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ๋ค ๐
+) Controller๋ ํน์ ํ ์ฌ์ฉ์, ํน์ ์ํ์ ๊ฒฐํฉํด์๋ ์ ๋๋ค.
๊ธฐ์กด์๋ UserId๋ chessGame ๊ฐ์ ํน์ ํ ์ธ์คํด์ค๋ฅผ ํ๋๋ก ๊ฐ์ง๊ณ ์๋๋ก ๋ง๋ค์์๋๋ฐ, ์๊ฐํด๋ณด๋ฉด ์ปจํธ๋กค๋ฌ์ ๊ฒฝ์ฐ ์ฌ์ฉ์์ ์์ฒญ์ด ๋ค์ด์์ ๋ ์๋ต์ ํด์ผ ํ๋๋ฐ ํน์ ํ ์ฌ์ฉ์์๊ฒ ๊ฒฐํฉ์ ํด๋ฒ๋ฆฌ๋ฉด ์ฑ ์์ด ๋ง์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
Controller๋ ์ธ๋ถ์์ ๋ค์ด์ค๋ input ๊ฐ์ ๋ํ ์ฒ๋ฆฌ, ์ธ๋ถ๋ก ๋๊ฐ output์ ๋ํ ์ฒ๋ฆฌ, ์ ์ ํ service๋ฅผ ํธ์ถํ๋ ๊ณณ์ด๋ผ๋ ๊ฒ์ ํญ์ ๋ช ์ฌํ๋๋ก ํ์ ๐
๐ฌ DTO๋ ์ด๋์์ ๋ณํํด์ผ ํ ๊น?
public final class BoardDto {
private final Map<PositionDto, PieceDto> board;
private BoardDto(final Map<PositionDto, PieceDto> board) {
this.board = board;
}
public static BoardDto from(final Map<Position, Piece> board) {
final Map<PositionDto, PieceDto> boardDto = new HashMap<>();
for (Position position : board.keySet()) {
boardDto.put(PositionDto.from(position.getRank(), position.getFile()),
PieceDto.from(board.get(position)));
}
return new BoardDto(boardDto);
}
public Map<PositionDto, PieceDto> getBoard() {
return Collections.unmodifiableMap(board);
}
}
์ฌ์ค ๋ ๋ฒจ 1 ๋ฏธ์ ์ ์งํํ๋ฉด์ 'Dto๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์์๊น?'๋ผ๋ ์๊ฐ์ ํ์๋๋ฐ, ์ฒด์ค ๋ฏธ์ ์ ํ๋ฉด์ ์ฒ์์ผ๋ก ์ฌ์ฉํ๊ฒ ๋์๋ค.
ํ์ฌ ์์ ์ฝ๋๋ ์ฒด์คํ์ ๋ํด view๊ฐ ์ถ๋ ฅํ๊ธฐ ์ํด dto๋ก ๋ณํํ๋ ๋ก์ง์ธ๋ฐ, ๋ฆฌ๋ทฐ์ด๋์ dto๊ฐ ๋๋ฉ์ธ์ ๋ชจ๋ฅด๋๋ก ๋ง๋๋ ๊ฑด ์ด๋ ๋๊ณ ์ฌ์ญค๋ณด์ จ๋ค. ๊ทธ๋์ ๋ ํ ๋ฒ ๊ณ ๋ฏผ์ ์๊ฐ์ ๊ฑฐ์น๊ฒ ๋์๋ค. ์ DTO๊ฐ ๋๋ฉ์ธ์ ๋ชฐ๋ผ์ผ ํ ๊น...?
์ฌ์ค ์ฒ์ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ์์ ๋๋ service layer๋ฅผ ์์ฑํด์ ํด๋น ๊ณ์ธต์์ ๋ณํ์ ํ๋ผ๋ ๋ง๋ก ๋ฐ์๋ค์๋ค.
๋งํด ํ์ธ๋ฌ๊ฐ ๋งํ Service Layer์ ์ ์๋ฅผ ๋ณด์์ ๋, Service๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ๊ณ ์ ์ ๋ฐ ๋น์ฆ๋์ค ๋ก์ง ๋ฑ, ๋๋ฉ์ธ์ ๋ํ ์บก์ํ๋ฅผ ์งํํ๋ ๊ณณ์ด๋ผ๊ณ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฝ ์ปจํธ๋กค๋ฌ์์ DTO๋ก ๋ณํํ๋ ๋ก์ง์ด ์๊ธด๋ค๋ฉด, ๋๋ฉ์ธ์ ๋ณ๊ฒฝ์ด ์ปจํธ๋กค๋ฌ์๊ฒ๋ ์ํฅ์ ๋ผ์น๊ฒ ๋๊ธฐ ๋๋ฌธ์ ์บก์ํ๊ฐ ๊นจ์ง๊ฒ ๋์ด Service Layer์์ ํ๋ ๊ฒ ๋ง๋ค๋ ์๊ฐ์ด ๋ค์๋ค.(ํ ์ฝ๋ธ ๊ฐ์ฌํฉ๋๋ค ๐โ๏ธ)
public final class ChessBoardService {
private final PieceService pieceService;
private final PositionService positionService;
public ChessBoardService(final PieceService pieceService, final PositionService positionService) {
this.pieceService = pieceService;
this.positionService = positionService;
}
public ChessBoardDto createChessBoardDto(final Map<Position, Piece> chessBoard) {
final Map<PositionDto, PieceDto> boardDto = new HashMap<>();
for (Position position : chessBoard.keySet()) {
boardDto.put(
positionService.createPositionDto(position.getRank(), position.getFile()),
pieceService.createPieceDto(chessBoard.get(position)));
}
return new ChessBoardDto(boardDto);
}
}
๊ทธ๋์ ์๋ฐ ์ด์ํ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋์๋ค ๐
ํ์ง๋ง, ๋ฆฌ๋ทฐ์ด๋์ด ๋ค์๊ณผ ๊ฐ์ ์๊ฒฌ์ ์ฃผ์ จ๋ค.
ํ์ฌ ์๋น์ค๋ฅผ dto๋ฅผ ๋ง๋๋ factory์ฒ๋ผ ์ฌ์ฉํ๊ณ ๊ณ์๋๋ฐ์ใ ใ .. ์๋น์ค์ ์ญํ ์ ์ด๊ฒ ์๋๋๋ค.
์๋น์ค์ ์ญํ ์ ์ฐพ์๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์์.
์๋น์ค๋ ๋น์ง๋์ค ๋ก์ง์ ํ๋ฆ์ ๋ด๋นํ๋ ํด๋์ค์ ๋๋ค. dto๋ฅผ ๋ง๋๋ factory ์ญํ ์ ํ๋๊ฒ ์๋๋๋ค!
์๋๋ ์๋น์ค๊ฐ ์๋ค๋ฉด Controller์์ ๋น์ง๋์ค ๋ก์ง์ ํธ์ถํ์ฌ ์ฌ์ฉํ๊ฒ ๋ ํ ๋ฐ์. ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ปค์ง๋ฉด, ๋ณต์กํด์ง๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ํฉ์ด์ง ๋ก์ง์ ํ๋๋ก ๋ฌถ์ด์ ๊ณ ์์ค์ ํํ๋ก ์ถ์ํํด์ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋น์ค์ ๋๋ค.
๋ฐ๋ผ์ ๋น์ง๋์ค ๋ก์ง์ ํ๋ฆ์ ๊ณ ์์ค์ผ๋ก ๋ฌถ๊ธฐ ๋๋ฌธ์ ์๋น์ค์ ๋ฉ์๋๋ ํ๋์ applicaiton ์ ๊ธฐ๋ฅ์ ํ๊ฒ ๋๋๊ฒ์ด์ฃ .
ํ์ฌ ๋ด๊ฐ ์์ฑํ ์ฝ๋๋ mapper ๊ธฐ๋ฅ ๊ทธ ์ด์, ๊ทธ ์ดํ๋ ํ์ง ์๊ณ ๋ณ๋์ ๋น์ฆ๋์ค ๋ก์ง ์ญ์ ์กด์ฌํ์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋์ ์์ mapper๋ผ๋ ์ด๋ฆ์ util ํด๋์ค๋ฅผ ์์ฑํ์ฌ ํด๋น ํด๋์ค์์ ๋ณํ์ ๋ด๋นํ๋๋ก ๋ณ๊ฒฝํ์๋ค.
public final class ChessBoardDtoMapper {
public static ChessBoardDto createChessBoardDto(final Map<Position, Piece> chessBoard) {
final Map<PositionDto, PieceDto> boardDto = new HashMap<>();
for (Position position : chessBoard.keySet()) {
boardDto.put(
PositionDtoMapper.createPositionDto(position.getRank(), position.getFile()),
PieceDtoMapper.createPieceDto(chessBoard.get(position)));
}
return new ChessBoardDto(boardDto);
}
}
์ด๋ ๊ฒ ๊ตฌํํ ๋๋ถ์ ๋๋ฉ์ธ๊ณผ dto ์ฌ์ด์ ์์กด์ฑ์ ์์ ํ ๋์ด์ง๊ฒ ๋์๋ค.
์ฝ๋๋ฅผ ์์ฑํ๋ฉด์ ์๋น์ค ๋ ์ด์ด์ ์ญํ ์ ๋ํด์๋ ๋ค์ ๊ณ ๋ฏผ์ ํ๊ฒ ๋์๋ค.
๊ทธ๋ฅ ํ ๋ง๋๋ก ์ ๋ฆฌํ๋ฉด ๋น์ฆ๋์ค ๋ก์ง์ ์งํฉ + ๊ทธ๋ฆฌ๊ณ ์ถ์ํ์ ๋ชฉ์ .
์๋น์ค ๋ ์ด์ด๋ ํ๋์ ๊ธฐ๋ฅ์ผ๋ก์, ๋น์ฆ๋์ค ๋ก์ง์ ํ๋ฆ์ ๋ด๋นํ๊ฒ ๋๋ค.
๋ ๋ฒ์งธ๋ก, ๋ฆฌ๋ทฐ์ด๋์ ์๊ฒฌ๊ณผ ๋ง๋ถ์ฌ์, ์ dto๋ ๋๋ฉ์ธ์ ์๋ฉด ์ ๋๋์ง์ ๋ํ ์๊ฒฌ์ ๋ค์๊ณผ ๊ฐ์ด ์ ๋ฆฌํ๋ค.
dto์ ์๋ฏธ๋ก ์ ๊ด์ ์ผ๋ก ์๊ฐํด๋ณด์์ ๋, dto๋ view์ controller ์ฌ์ด์์ ๋๋ฉ์ธ์ ์์กด์ ๋๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
ํ์ง๋ง dto๊ฐ ๋๋ฉ์ธ์ ์๊ณ ์๋ค๋ฉด, dto์ ์๋ฏธ ์์ฒด๊ฐ ํด์๋๋ค. ๋จ์ํ getter, setter๋ฅผ ํตํด ๊ฐ์ ์ฑ์์ฃผ๊ณ , ๊ฐ์ ๋ฐํํ๋ ๋ก์ง๋ง ํ์ํ ๋ฟ์ด๊ณ , ํ์ํ ๊ณณ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ฃผ๋ ์ญํ ๋ก ์ถฉ๋ถํ๋ค.
+ ์ถ๊ฐ์ ์ผ๋ก, ๊ทธ๋ ๋ค๋ฉด enum ๋๋ฉ์ธ์ ๋ํด์๋ dto๋ก ๋ณํํด์ผ ํ ๊น? ๋ผ๋ ๊ณ ๋ฏผ๋ ์งํํ๋ค.
ํ์ฌ ์ฌ์ฉ๋๊ณ ์๋ pieceType์ ๊ฒฝ์ฐ ๋ณธ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค์ํ ๋๋ฉ์ธ์ด๊ธฐ๋ ํ๊ณ , '๋๋ฉ์ธ'์ผ๋ก์ ์ญํ ์ ํ๊ณ ์๊ธฐ ๋๋ฌธ์ dto๋ก ๋ณํํ์ฌ ๋ฐํํ๋ ๊ฒ ๋ง์ ๊ฒ ๊ฐ๋ค๋ ๊ฒฐ๋ก ์ ๋ด๋ ธ๋ค.
public final class PieceDto {
private final String pieceType;
private final String campType;
public PieceDto(final String pieceType, final String campType) {
this.pieceType = pieceType;
this.campType = campType;
}
}
๊ทธ๋์ enum ํ์ ์ธ pieceType, campType์ ๋ํด์๋ String์ผ๋ก ๋ณํ์ ์งํํ์๋ค.
๐ฌ ๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ
4๋จ๊ณ ๋ฏธ์ ์์ DAO์ ๊ด๋ จ๋ ํ ์คํธ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์๋ค.
public class MockChessGameDao implements ChessGameDao {
private final Map<Long, ChessGameEntity> STORAGE = new ConcurrentHashMap<>();
private final AtomicLong pk = new AtomicLong(0L);
@Override
public Optional<ChessGameEntity> findByUserId(final long userId) {
return STORAGE.values().stream()
.filter(chessGameEntity -> chessGameEntity.getUserId().equals(userId))
.map(chessGameEntity -> new ChessGameEntity(chessGameEntity.getId(), chessGameEntity.getCurrentCamp(),
chessGameEntity.getUserId()))
.findFirst();
}
@Override
public Long insert(final ChessGameEntity chessGameEntity) {
final long key = pk.addAndGet(1L);
final ChessGameEntity savedChessGameEntity = new ChessGameEntity(key,
chessGameEntity.getCurrentCamp(), chessGameEntity.getUserId());
STORAGE.put(key, savedChessGameEntity);
return pk.longValue();
}
@Override
public void updateCurrentCampById(final long id, final CampType currentCamp) {
final ChessGameEntity chessGameEntity = STORAGE.get(id);
STORAGE.put(id, new ChessGameEntity(chessGameEntity.getId(), currentCamp.name(), chessGameEntity.getUserId()));
}
@Override
public void deleteByUserId(final long userId) {
STORAGE.keySet().stream()
.filter(key -> Objects.equals(STORAGE.get(key).getUserId(), userId))
.forEach(STORAGE::remove);
}
}
Map์ ํตํด์ ๊ฐ์ง ์คํ ๋ฆฌ์ง๋ฅผ ๋ง๋ค๊ณ , ์ค์ DB ์ฐ์ฐ์ด ์ํ๋๋ ๊ฒ์ฒ๋ผ ๋ง๋ค์๋ค.
Test Double ๊ธฐ๋ฒ์ Fake๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๋ณผ ์ ์๋ค.
ํ์ง๋ง ๋ช๋ช ํฌ๋ฃจ๋ค์ ์ค์ ๋ก DB ์ฐ๊ฒฐ์ ๋ํ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ณ , DB๋ฅผ ๋กค๋ฐฑํ๋ ํํ๋ก ์์ฑํ์ฌ์ ์ด๋ฐ ์์ผ๋ก ์์ฑํ๋ ๊ฒ ์ฌ๋ฐ๋ฅธ ์๋์ธ์ง๊ฐ ๊ถ๊ธํ๋ค. ๋ฆฌ๋ทฐ์ด๋์ ์ด์ ์ด๋ ๊ฒ ๋ตํด์ฃผ์ จ๋ค.
db์ ์ฐ๊ฒฐํ์ฌ ํตํฉํ ์คํธ๋ฅผ ์์ฑํ๋ ค๋ ์๋๊ฐ ์๋๊ณ , ์ ๋ํ ์คํธ๋ฅผ ์์ฑํ์๋ ค๊ณ ํ๋ ์๋๋ผ๋ฉด ์ด๋ ๊ฒ ์์ฑํ์ ๋ ๋ฌด๋ฐฉํ๋ค๊ณ ์๊ฐํฉ๋๋ค!
ํตํฉ ํ ์คํธ์ ๋จ์ ํ ์คํธ...?
๋๋ ์ง๊ธ๊น์ง ๊ธฐ๋ฅ๋ณ๋ก ํ ์คํธ ํ๋ ๊ฒ์ ๋จ์ ํ ์คํธ (ex. ๋๋ฉ์ธ ์์ญ), ๊ธฐ๋ฅ์ด ๋ชจ์์ง ๋ถ๋ถ์ ํ ์คํธํ๋ ๊ฒ์ ํตํฉ ํ ์คํธ (ex. ์ปจํธ๋กค๋ฌ)๋ผ๊ณ ์๊ฐํ์๋ค. ๋ฆฌ๋ทฐ์ด๋์ ๋ต๋ณ์ ๋ฐ๊ณ ๋ด๊ฐ ์๋ชป ์๊ฐํ๊ณ ์์๋ค๋ ๊ฒ์ ๊นจ๋ซ๊ณ , ๋ด ๋๋ฆ๋๋ก ๋ ํ ์คํธ์ ๋ํ ์ ์๋ฅผ ๋ด๋ ค๋ณด์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฆฌ๋ทฐ์ด๋์ ์ด์ ๋ํด์ ๋ค์๊ณผ ๊ฐ์ด ๋๋ต์ ํด์ฃผ์ จ๋ค.
๊ฐ์ฅ์์ ๋จ์๋ก ๋ค๋ฅธ ํ๋ ฅ๊ฐ์ฒด ์์ด ํ ์คํธ๋ฅผ ํ๋ค๋ฉด, ๋จ์ํ ์คํธ
ํ ์คํธ๋ฅผ ์งํํ ์ ํ๋ ฅ๊ฐ์ฒด๋ฅผ ํตํด ํ ์คํธ๋ฅผ ์งํํ๋ฉด ํตํฉํ ์คํธ
ํ ์คํธํ๋ ๋์ ์ด์ธ์ ๊ฒ์ ์ธ๋ถ์ ๋ฆฌ์์ค๋ผ๊ณ ๋ณธ๋ค๋ฉด ์ง๊ธ๊น์ง ์๊ฐํ๋ ํ ์คํธ์ ๊ฐ๋ ๊ณผ ์ด๋ ์ ๋ ๋ถํฉํ๋ ๊ฒ ๊ฐ๊ธฐ๋ ํ๋ค.
ํ์ฌ ํ๋ก๊ทธ๋จ์ ๋์ ์ธ๋ถ ๋ฆฌ์์ค (ex. ์ธ๋ถ api, DB) ๋ฑ์ด ํฌํจ๋์ด์ผ ํตํฉ ํ ์คํธ์ธ ๊ฑด๊ฐ?๋ผ๊ณ ์๊ฐํ์๋๋ฐ, ๊ทธ ๊ด์ ๋ณด๋ค๋ ๋ด๊ฐ ๊ตฌํํ ๊ธฐ๋ฅ์์ ์ธ๋ถ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํด์ผ ํ ๋, ํด๋น ๋ฆฌ์์ค๋ฅผ mocking์ ํด์ ์ค์ ๋ก ํ ์คํธ ํ๋ ๋์์ด ํ๋์ ๊ธฐ๋ฅ์ด๋ผ๋ฉด ๋จ์ ํ ์คํธ๋ผ๊ณ ๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค.
์ฆ, mocking์ ํตํด ์ธ๋ถ์ ๋ฆฌ์์ค๋ฅผ ์ ์ธ์ํค๊ณ ๋ด๊ฐ ํ ์คํธํ ๋์์ ๋ํด์๋ง ํ ์คํธํ๋ค๋ฉด ์ด๋ ๋จ์ ํ ์คํธ๊ฐ ๋๋ ๊ฒ์ด๊ณ ,
๊ทธ๊ฒ ์๋๋ผ ์ค์ ํ๋ ฅ ๊ฐ์ฒด ์์ฒด์ ํจ๊ป ํ ์คํธ๋ฅผ ์งํํ๋ค๋ฉด ํตํฉ ํ ์คํธ๋ก ๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค!
๊ทธ๋์ ๋ง์ฝ ์คํ๋ง์์ h2 ๊ฐ์ in-memory database๋ฅผ ํ์ฉํ์ฌ repository๋ฅผ ํ ์คํธํ๋ค๋ฉด, ์ค์ DB ๋ฆฌ์์ค์ ์ฐ๊ฒฐ์ด ์๊ธฐ๊ธฐ ๋๋ฌธ์ ํตํฉ ํ ์คํธ๋ผ๊ณ ๋ณผ ์ ์๋ค! ๋ฐ๋ฉด์, ์์ ๋ก๊ทธ์ธ ๊ฐ์ด ์ธ๋ถ api ์ฐ๋์ mockingํ์ฌ ํจ์คํ๊ฒ ๋๋ค๋ฉด ํด๋น ํ ์คํธ๋ ๋จ์ ํ ์คํธ๊ฐ ๋๋ค. ์ด ๊ธฐํ์ ๋ ๊ฐ๋ ์ ๋ช ํํ๊ฒ ์ก์ ๊ฒ ๊ฐ์์ ๋ฟ๋ฏํ๋ค...!
๋ฐ์๊ฒ ์งํํ๋ ๋งํผ ๋ฟ๋ฏํ๋ ์ฒด์ค ๋ฏธ์ ... ๐ฅน
์กฐ๊ธ ๋ ๋ฆฌ๋ทฐ์ด๋์ด๋ ๋ง์ ๋ํ๋ฅผ ๋๋ด๋ค๋ฉด ์ข์์ ํ ๋ฐ ์์ฌ์์ด ๋จ๋๋ค.
๊ทธ๋๋ ํํ๋ ์๋ค! ๋ค์ ๋ฏธ์ ๋๋ ๋ ์ด์ฌํ ์งํํด์ผ๊ฒ ๋ค.
'์ฐ์ํํ ํฌ์ฝ์ค > ๋ ๋ฒจ 1' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ฐํ ์ฝ 5๊ธฐ] ๋ ๋ฒจ 1 ๋ ๋ฒจ ์ธํฐ๋ทฐ ์ ๋ฆฌ ๋ฐ ๊ฐ์ ํ๊ณ (4) | 2023.04.06 |
---|---|
[์ฐํ ์ฝ 5๊ธฐ] ๋ธ๋์ญ ๊ตฌํ ๋ฏธ์ ํ๊ณ (0) | 2023.04.04 |
[์ฐํ ์ฝ 5๊ธฐ] ์ฌ๋ค๋ฆฌ ํ๊ธฐ ๊ฒ์ ๋ฏธ์ ํ๊ณ (0) | 2023.04.03 |
[์ฐํ ์ฝ 5๊ธฐ] ์๋์ฐจ ๊ฒฝ์ฃผ ๊ฒ์ ํ๊ณ (0) | 2023.02.22 |
[์ฐํ ์ฝ 5๊ธฐ] 1์ฃผ์ฐจ ํ๊ณ ๋ก - ์ฐ๊ทน, ์๋์ฐจ ๊ฒฝ์ฃผ ๊ฒ์ ๊ตฌํํ๊ธฐ (2) | 2023.02.13 |