DevLog ๐Ÿ˜ถ

[์šฐํ…Œ์ฝ” 5๊ธฐ] ์ฒด์Šค ๊ฒŒ์ž„ ๊ตฌํ˜„ ๋ฏธ์…˜ ํšŒ๊ณ  ๋ณธ๋ฌธ

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค/๋ ˆ๋ฒจ 1

[์šฐํ…Œ์ฝ” 5๊ธฐ] ์ฒด์Šค ๊ฒŒ์ž„ ๊ตฌํ˜„ ๋ฏธ์…˜ ํšŒ๊ณ 

dolmeng2 2023. 4. 5. 22:27

์ œ๋‚˜๋ž‘ ํ•จ๊ป˜ํ•œ ๋„ค ๋ฒˆ์งธ ํŽ˜์–ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค.

๋ฏธ์…˜์„ ์ง„ํ–‰ํ•  ๋‹น์‹œ์—๋Š” ๋‚œ์ด๋„๊ฐ€ ํ™• ๋›ด ๋Š๋‚Œ์ด๋ผ ์–ด๋ ต๋‹ค๋Š” ์ƒ๊ฐ, ๊ทธ๋ฆฌ๊ณ  ์‹œ๊ฐ„์ด ๋„ˆ๋ฌด ์ด‰๋ฐ•ํ•˜๋‹ค๋Š” ์ƒ๊ฐ๋ฟ์ด์—ˆ๋Š”๋ฐ ๋‹ค ๋๋‚˜๊ณ  ๋‚˜์„œ ๋Œ์•„๋ณด๋‹ˆ๊นŒ ๋‚˜๋ฆ„๋Œ€๋กœ ์ž˜ ํ•ด๋‚ธ ๊ฒƒ ๊ฐ™๋‹ค. (๋ฌผ๋ก ... ์ฝ”๋“œ๊ฐ€ ๋งˆ์Œ์— ๋“ ๋‹ค๋Š” ๋ง์€ ์•„๋‹ˆ๋‹ค ๐Ÿฅน ์ •๋ง ๋งŽ์ด ๋ถ€์กฑํ•˜๋‹ค...)

๊ทธ๋ž˜๋„ ๋ ˆ๋ฒจ 1 ๋งˆ์ง€๋ง‰ ๋ฏธ์…˜๊นŒ์ง€ ์–ด๋–ป๊ฒŒ๋“  ์˜จ ๋‚ด ์ž์‹ ์ด ๋Œ€๊ฒฌํ•˜๋‹ค! ์•ž์œผ๋กœ๋„ ํž˜๋‚ด์ž ๐Ÿ’ช

โœ”๏ธ ์ž‘์„ฑํ•œ ์ฝ”๋“œ

 

GitHub - Cl8D/java-chess: ์ฒด์Šค ๊ฒŒ์ž„ ๊ตฌํ˜„์„ ์œ„ํ•œ ์ €์žฅ์†Œ

์ฒด์Šค ๊ฒŒ์ž„ ๊ตฌํ˜„์„ ์œ„ํ•œ ์ €์žฅ์†Œ. Contribute to Cl8D/java-chess development by creating an account on GitHub.

github.com

โœ”๏ธ 1์ฐจ PR

 

[1, 2๋‹จ๊ณ„ - ์ฒด์Šค] ์ ธ๋‹ˆ(์ด์ง€์›) ๋ฏธ์…˜ ์ œ์ถœํ•ฉ๋‹ˆ๋‹ค. by Cl8D · Pull Request #485 · woowacourse/java-chess

์•ˆ๋…•ํ•˜์„ธ์š”, ์„œ๋ธŒ์›จ์ด! 5๊ธฐ ๋ฐฑ์—”๋“œ ํฌ๋ฃจ ์ ธ๋‹ˆ์ž…๋‹ˆ๋‹ค โ˜ƒ๏ธ ์ด๋ฒˆ ๋ฏธ์…˜์€ ๋„ˆ๋ฌด ๋ถ€์กฑํ•œ ์ ์ด ๋งŽ์•„์„œ ๋ฆฌ๋ทฐ ์š”์ฒญ ๋“œ๋ฆฌ๊ธฐ๋„ ๋ฏผ๋งํ•˜๋„ค์š”... ๐Ÿ’ฆ ๋ฏธ์…˜์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋ช…๋ น์–ด์— ๋Œ€ํ•ด ์ƒํƒœ ํŒจํ„ด์„ ์ ์šฉํ•˜์—ฌ

github.com

โœ”๏ธ 2์ฐจ PR

 

[3, 4 ๋‹จ๊ณ„ - ์ฒด์Šค] ์ ธ๋‹ˆ(์ด์ง€์›) ๋ฏธ์…˜ ์ œ์ถœํ•ฉ๋‹ˆ๋‹ค. by Cl8D · Pull Request #604 · woowacourse/java-chess

์•ˆ๋…•ํ•˜์„ธ์š”, ์„œ๋ธŒ์›จ์ด! ์ ธ๋‹ˆ์ž…๋‹ˆ๋‹ค โ˜ƒ๏ธ 3, 4๋‹จ๊ณ„๋Š” ์‹œ๊ฐ„์— ์ซ“๊ฒจ ๊ธ‰ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š๋ผ ๋‚ด๋ถ€ ๋กœ์ง์ด ๋‹ค์†Œ ์—‰๋ง์ธ ๊ฒƒ ๊ฐ™๋„ค์š”... ๐Ÿฅฒ ๊ถ๊ธˆํ•œ ์ ์€ ์ฝ”๋“œ ์ปค๋ฉ˜ํŠธ๋กœ ๋‹ฌ์•„๋‘๊ฒ ์Šต๋‹ˆ๋‹ค! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ™‡‍โ™€๏ธ

github.com

โœ”๏ธ ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ

[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ํ•˜์—ฌ ํŒจ์Šคํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ํ•ด๋‹น ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๋œ๋‹ค. ์ด ๊ธฐํšŒ์— ๋‘ ๊ฐœ๋…์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์žก์€ ๊ฒƒ ๊ฐ™์•„์„œ ๋ฟŒ๋“ฏํ–ˆ๋‹ค...!

 


๋ฐ”์˜๊ฒŒ ์ง„ํ–‰ํ–ˆ๋˜ ๋งŒํผ ๋ฟŒ๋“ฏํ–ˆ๋˜ ์ฒด์Šค ๋ฏธ์…˜... ๐Ÿฅน

์กฐ๊ธˆ ๋” ๋ฆฌ๋ทฐ์–ด๋‹˜์ด๋ž‘ ๋งŽ์€ ๋Œ€ํ™”๋ฅผ ๋‚˜๋ˆด๋‹ค๋ฉด ์ข‹์•˜์„ ํ…๋ฐ ์•„์‰ฌ์›€์ด ๋‚จ๋Š”๋‹ค.

๊ทธ๋ž˜๋„ ํ›„ํšŒ๋Š” ์—†๋‹ค! ๋‹ค์Œ ๋ฏธ์…˜ ๋•Œ๋Š” ๋” ์—ด์‹ฌํžˆ ์ง„ํ–‰ํ•ด์•ผ๊ฒ ๋‹ค.

Comments