Skip to content

villainscode/coding-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

18 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Coding Guide for Java Programmer By ์ฝ”๋“œ๋นŒ๋Ÿฐ

๋ณธ ๋‚ด์šฉ์€ ํ•œ๋น›๋ฏธ๋””์–ด์—์„œ ์ถœ๊ฐ„ํ•œ ์ œ ์ฑ…(๊ฐœ๋ฐœ์ž ๊ธฐ์ˆ  ๋ฉด์ ‘ ๋…ธํŠธ)์˜ ์ผ๋ถ€ ๋‚ด์šฉ์„ ๋ณด๊ฐ•ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋งŒ๋“  ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ ์ž…๋‹ˆ๋‹ค.
์„ค๋ช…์—์„œ๋Š” ํƒ€์ดํ•‘์„ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ์กด๋Œ€๋ฅผ ์ƒ๋žตํ–ˆ์œผ๋‹ˆ ์–‘ํ•ด ๋ฐ”๋ž๋‹ˆ๋‹ค.
๋งŒ์•ฝ ๋‚ด์šฉ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ์˜ค/ํƒˆ์ž๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ villainscode@gmail.com์œผ๋กœ ๋ฉ”์ผ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๊ฐœ์ • ์ด๋ ฅ

ํ˜„์žฌ ๋ฒ„์ „ v.1.0.0 (2024.05.09)

  • ๋” ๋‹ค์–‘ํ•œ ์ฝ”๋“œ ์šฉ๋ก€๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐœ์ • ์ด๋ ฅ์€ ์—…๋ฐ์ดํŠธ ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

Table of contents generated with markdown-toc

๐Ÿ“– ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ

๋“ค์–ด๊ฐ€๊ธฐ์— ์•ž์„œ

์ด ๋‚ด์šฉ์€ ์•„๋ž˜์˜ ์„œ์ ๊ณผ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€๋‹ค. ๊ฐ์ข… ์˜ˆ์ œ ์ฝ”๋“œ๋“ค์€ ์ฝ”๋“œ๋นŒ๋Ÿฐ ๋ณธ์ธ์˜ ๊ฐœ์ธ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜์—ฌ ์ฑ—GPT์˜ ๋„์›€์„ ๋ฐ›์•˜๋‹ค.GPT๋งŒ์‰!

์†Œ๊ฐœ

์ฐธ๊ณ  ์„œ์  ๋ฐ ๋งํฌ

์ธํ”„๋Ÿฐ ๊ฐ•์˜

์ฝ”๋”ฉ ๊ฐ€์ด๋“œ ๊ฐœ์š”

๐Ÿ’ก ๊ฐœ์š”

ํŒ€ ๋‚ด ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ์œ„ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋„ค์ด๋ฐ, ์ฝ”๋“œ ์ค€์ˆ˜ ์‚ฌํ•ญ์˜ ์˜์‚ฌ๊ฒฐ์ • ํšŸ์ˆ˜๋ฅผ ์ค„์ด๊ณ  ๋‹จ์ˆœํ•˜๊ณ  ์œ ์—ฐํ•œ ํ†ต์ผ๊ฐ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ง€ํ–ฅํ•จ์œผ๋กœ์จ ๋ณด๋‹ค ํšจ์œจ์ ์ธ ํŒ€ ์ฝ”๋“œ ๋ฌธ์„œ๋ฅผ ์ƒ์‚ฐํ•œ๋‹ค.

  • ์ƒˆ๋กœ ํ•ฉ๋ฅ˜ํ•œ ๋ฉค๋ฒ„๋„ ํŒ€์˜ ๊ฐ€์ด๋“œ ๋ผ์ธ์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋„๋ก, ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ + ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๊ฐ€์ด๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
  • ์ฝ”๋“œ์˜ ๋„ค์ด๋ฐ๋งŒ์œผ๋กœ๋„ ๊ธฐ๋Šฅ์„ ์•Œ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•œ๋‹ค.
  • ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ + ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๊ฐ€์ด๋“œ๋Š” ํŒ€๋‚ด ๊ฐœ๋ฐœ ๋ฌธํ™”๋กœ์จ ์—„๊ฒฉํ•œ ์ค€์ˆ˜๋ฅผ ์ง€ํ–ฅํ•œ๋‹ค.
  • ํˆด์˜ ํ†ต์ผ์„ฑ, ๋‹จ์ถ•ํ‚ค์˜ ๊ธฐ๋ณธ ์„ค์ •ํ™”๋ฅผ ์ง€ํ–ฅํ•˜์—ฌ ์ฝ”๋“œ ๋ฆฌ๋ทฐ์‹œ ๋‹จ์ถ•๊ธฐ ์‚ฌ์šฉ๋“ฑ์˜ ํŒ ๋˜ํ•œ ๊ณต์œ  ๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ๋‹จ์ˆœํžˆ ์ฝ”๋“œ์˜ ํ’ˆ์งˆ๋งŒ ๋…ผ์˜ ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฒ„๊ทธ๋‚˜ ๋ฐฉ์–ด ์ฝ”๋“œ ํ•„์š” ์—ฌ๋ถ€, ๊ด€ํ–‰์  ๋ช…๋ช…์„ ์ค€์ˆ˜ ํ•˜์˜€๋Š”์ง€ (by ์ฝ”๋”ฉ ๊ฐ€์ด๋“œ), ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ์—†๋Š”์ง€ ๊ณ ๋ฏผํ•ด์„œ ๋ฆฌ๋ทฐํ•˜๊ณ  ํ•ญ์ƒ ๋ณธ ๋ฌธ์„œ ์ด์™ธ์˜ ๋ฐฉ์‹์—์„œ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋Š” ๊ทผ๊ฑฐ์ž๋ฃŒ๋ฅผ ์ฐพ์•„ ๋ณด์ถฉํ•˜๋„๋ก ํ•œ๋‹ค.
  • ๊ฐœ์„ ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์™œ ๊ฐœ์„ ํ•ด์•ผ ํ•˜๋Š”๊ฐ€? ์— ๋Œ€ํ•ด์„œ ์ถฉ๋ถ„ํžˆ ์„ค๋ช…์ด ํ•„์š”ํ•˜๋‹ค. ์„ค๋ช…์ด ์—†๋‹ค๋ฉด ๊ฒฐ๊ตญ ์ฝ”๋“œ์— ํŠธ์ง‘์„ ์žก๊ฒ ๋‹ค๋Š” ๊ฒƒ ๋ฐ–์— ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ œ์•ˆ๊ณผ ์ด์œ ์— ๋Œ€ํ•ด์„œ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•œ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ž๋ฐ” ์ฝ”๋”ฉ ๊ทœ์น™

๊ธฐ๋ณธ์ ์ธ ์šฉ์–ด

  • Value Object : ๋น„์ฆˆ๋‹ˆ์Šค ์šฉ์–ด๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด
  • Entity : ์†์„ฑ์ด ์•„๋‹Œ ์‹๋ณ„์„ฑ์„ ๊ธฐ์ค€์œผ๋กœ ์ •์˜๋˜๋Š” ๋„๋ฉ”์ธ ๊ฐ์ฒด, ์—ฌ๋Ÿฌ Value Object๋กœ ๊ตฌ์„ฑ
  • Service : ๋„๋ฉ”์ธ ๊ฐ์ฒด์— ํฌํ•จํ•  ์ˆ˜ ์—†๋Š” ๋™์ž‘, ๋กœ์ง์ ์ธ ์—ฐ์‚ฐ์„ ๊ฐ–๋Š” ๊ฐ์ฒด
  • Aggregate : ์—ฐ๊ด€๋œ Value Object์™€ Entity์˜ ๋ฌถ์Œ
  • Factory : ๋ณต์žกํ•œ Entity, Aggregate๋ฅผ ์บก์Šํ™”ํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๋™์‹œ์— ์ƒ์„ฑ
  • Repository : Aggregate์˜ ์˜์†์„ฑ ๋ฐ ๋“ฑ๋กยท์ˆ˜์ •ยท์‚ญ์ œยท์กฐํšŒ ์‹œ ์ผ๊ด€์„ฑ ๊ด€๋ฆฌ

ํด๋ž˜์Šค์™€ ๊ฐ์ฒด, ๊ฐ์ฒด์™€ ์ธ์Šคํ„ด์Šค

ํด๋ž˜์Šค : ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์„ค๊ณ„ ์ฝ”๋“œ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  • ์ƒ์„ฑ์ž
  • ์†์„ฑ
  • ๋ฉ”์„œ๋“œ

๊ตฌ์ฒด์ ์ธ ๊ฐ’์„ ๊ฐ€์ง„ ์ƒํƒœ๋ผ๊ธฐ ๋ณด๋‹ค๋Š” ์ถ”์ƒ์ ์ธ ๊ฐœ๋…

๊ฐ์ฒด : ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ตฌ์ฒด์ ์ธ ๊ฐœ์ฒด. ํด๋ž˜์Šค์—์„œ ์ •์˜๋œ ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ง€๋‹Œ ์ƒํƒœ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ํด๋ž˜์Šค์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์˜ ์†์„ฑ๊ณผ ํ–‰๋™์„ ์ด์šฉํ•˜์—ฌ ์‹ค์ œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

ํด๋ž˜์Šค : ํด๋ž˜์Šค๋Š” ๊ฑด์ถ•๋ฌผ์˜ ์„ค๊ณ„๋„์™€ ๊ฐ™์€ ๊ฐœ๋…์ด๊ณ  ๊ฐ์ฒด๋Š” ์„ค๊ณ„๋„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ง‘๊ณผ ๊ฐ™๋‹ค.
ํด๋ž˜์Šค๋Š” ๋ฐ์ดํ„ฐ์™€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์ง‘ํ•ฉ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.
์ง‘์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณด๋ฉด ๋ฐฉ์˜ ์ˆ˜, ํฌ๊ธฐ, ํ™”์žฅ์‹ค์˜ ์ˆ˜, ์™ธ๊ด€์˜ ์ƒ‰๊น” ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์ง‘์œผ๋กœ์„œ์˜ ํ•„์ˆ˜์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ธ์Šคํ„ด์Šค : ์ธ์Šคํ„ด์Šค๋Š” ํŠน์ • ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์‹ค์ œ๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋กœ ์ €๋งˆ๋‹ค ๊ณ ์œ ํ•œ ๊ฐ’(์ฐธ์กฐ๊ฐ’)์„ ์ง€๋‹ˆ๊ณ  ์žˆ๋‹ค.

๊ฐ์ฒด๊ฐ€ [์ง‘]์ด๋ผ๊ณ  ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐœ๋…์ด๋ผ๋ฉด ์ธ์Šคํ„ด์Šค๋Š” ์ง‘ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” [์šฐ๋ฆฌ์ง‘, ์˜ํฌ๋„ค ์ง‘, ์ฒ ์ˆ˜๋„ค ์ง‘] ์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ฐ๊ฐ์˜ ์ง‘์€ ์„œ๋กœ ๋‹ค๋ฅธ ์†์„ฑ์„ ๊ฐ€์งˆ์ˆ˜ ์žˆ์ง€๋งŒ ๋ชจ๋‘ ์ง‘ ํด๋ž˜์Šค์˜ ํŠน์„ฑ๊ณผ ๊ธฐ๋Šฅ์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ž˜์Šค์™€ ๊ฐ์ฒด๋Š” 1:N์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ , ๊ฐ์ฒด์™€ ์ธ์Šคํ„ด์Šค๋Š” 1:N์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.

๊ฐ์ฒด๋Š” ๋Ÿฐํƒ€์ž„(์‹คํ–‰ ์‹œ)์— ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋˜๋Š” ๋ฐ˜๋ฉด, ํด๋ž˜์Šค๋Š” ์ปดํŒŒ์ผ ์‹œ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋œ๋‹ค.

๋ฉ”์„œ๋“œ์™€ ํ•จ์ˆ˜

๋ฉ”์„œ๋“œ๋Š” ํŠน์ • ํด๋ž˜์Šค์— ์†ํ•˜๋ฉฐ, ๊ฐ์ฒด์˜ ์†์„ฑ์ด๋‚˜ ํ–‰๋™์„ ์ •์˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ์ฒด๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ๊ณผ ๋ฐ์ดํ„ฐ ์€๋‹‰์„ ๊ตฌํ˜„ํ•œ๋‹ค.

ํ•จ์ˆ˜๋Š” ์ข€ ๋” ๋ฒ”์šฉ์ ์ธ ๊ฐœ๋…์œผ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์กด์žฌํ•˜๋ฉฐ ํŠน์ • ์ž‘์—…์ด๋‚˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”, ์ž๋ฐ” ์ด์™ธ์˜ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ ์‚ฌ์šฉ๋˜๋Š” ๊ฐœ๋…์ด๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ ํ•จ์ˆ˜๋Š” ๋ฉ”์„œ๋“œ๋ณด๋‹ค ์ƒ์œ„์˜ ๊ฐœ๋…์ด์ง€๋งŒ, ์ฃผ๋กœ ์ž๋ฐ” ์ง„์˜์—์„œ๋Š” ์ดˆ๊ธฐ๋ถ€ํ„ฐ ๋ฉ”์„œ๋“œ๋ผ๋Š” ๋ช…๋ช…๋ฒ•์ด ์ต์ˆ™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ = ๋ฉ”์„œ๋“œ ๋ผ๊ณ  ํ‘œํ˜„์„ ํ•  ๊ฒƒ์ด๋‹ค.

๋‚˜์œ ์ฝ”๋“œ

๋‚˜์œ ์ฝ”๋“œ๊ฐ€ ์Œ“์ผ ์ˆ˜๋ก ํŒ€ ์ƒ์‚ฐ์„ฑ์€ ๋–จ์–ด์ง„๋‹ค.

์ตœ๋Œ€ํ•œ ๋น ๋ฅธ ๊ฐœ๋ฐœ์„ ์ถ”๊ตฌํ•˜๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ธธ์€ ์ตœ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ํด๋ฆฐํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•œ ๋ช‡๊ฐ€์ง€ ์›์น™์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ์ค‘๋ณต์„ ํ”ผํ•˜๋ผ.
  • ํ•œ๊ธฐ๋Šฅ๋งŒ ์ˆ˜ํ–‰ํ•˜๋ผ
  • ์ œ๋Œ€๋กœ ํ‘œํ˜„ํ•˜๋ผ
  • ์ž‘๊ฒŒ ์ถ”์ƒํ™”ํ•˜๋ผ.

์ข‹์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ช‡๊ฐ€์ง€ ๊ทœ์น™๋“ค

  1. ๋ณด์ด์Šค์นด์šฐํŠธ ๊ทœ์น™ : ์บ ํ”„์žฅ์€ ์ฒ˜์Œ ์™”์„ ๋•Œ๋ณด๋‹ค ๋” ๊นจ๋—ํ•˜๊ฒŒ ํ•ด๋†“๊ณ  ๋– ๋‚˜๋ผ.
  • ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ 
  • ์กฐ๊ธˆ ๊ธด ๋ฉ”์„œ๋“œ๋Š” ๋ถ„ํ• ํ•˜๊ณ 
  • ์•ฝ๊ฐ„์˜ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ 
  • ๋ณต์žกํ•œ if ๋ฌธ ํ•˜๋‚˜๋ฅผ ์ •๋ฆฌํ•˜๊ณ โ€ฆ
  1. ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์˜ ๋‹ค์„ฏ๊ฐ€์ง€ ์›์น™
  • SRP(Single Responsibility Principle) : ํด๋ž˜์Šค์—๋Š” ํ•œ ๊ฐ€์ง€ ๋ณ€๊ฒฝ ์ด์œ ๋งŒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.
  • OCP(Open Closed Principle) : ํด๋ž˜์Šค๋Š” ํ™•์žฅ์— ์—ด๋ ค ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ๋ณ€๊ฒฝ์— ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • LSP(Liskov Substitution Principle) : ์ƒ์†๋ฐ›์€ ํด๋ž˜์Šค๋Š” ๊ธฐ์ดˆ ํด๋ž˜์Šค๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • DIP(Dependency Inversion Principle) : ์ถ”์ƒํ™”๋Š” ์˜์กดํ•ด์•ผ ํ•˜๋ฉฐ, ๊ตฌ์ฒดํ™”๋Š” ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
  • ISP(Interface Segregation Principle) : ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ์„ ์ œ๊ณตํ•œ๋‹ค. (๋ถˆํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž‘๊ฒŒ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค)

์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„

์˜๋„๋ฅผ ๋ถ„๋ช…ํžˆ ๋ฐํ˜€์•ผ ํ•œ๋‹ค.

// ์˜๋ฏธ ์—†๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„
public void processData(Object data) {
  // ...
} // bad

// ์˜๋ฏธ ์žˆ๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„
public void calculateStudentGrade(List<Student> students) {
  // ...
} // good 

์กฐ๊ฑด์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋” ๋ช…ํ™•ํžˆ ์ฝํžŒ๋‹ค.

์กฐ๊ฑด๋ฌธ ๋ถ„๋ฆฌ ์ฝ”๋“œ

// ์ค‘์ฒฉ if ๋ฌธ 
if (user.isLogIn()) {
  if (user.isAdmin()) {
    // ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ํ‘œ์‹œ
  } else {
    // ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€ ํ‘œ์‹œ
  }
} else {
  // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ
} // bad 
// ์กฐ๊ฑด๋ฌธ ๋ถ„๋ฆฌ ๋ฐ ํ•จ์ˆ˜ ์‚ฌ์šฉ
if (user.isLogIn()) {
  renderUserPage(user);
} else {
  renderLoginPage();
} 

private void renderUserPage(User user) {
  if (user.isAdmin()) {
    renderAdminPage(user);
  } else {
    renderUserPage(user);
  }
} 

private void renderLoginPage() {
  // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ
} // good 

์กฐ๊ฑด๋ถ€ ํ‘œํ˜„์‹ ์‚ฌ์šฉ

// if ๋ฌธ ์‚ฌ์šฉ
if (user.getAge() >= 19) {
  // ์„ฑ์ธ์ž„์„ ์•Œ๋ฆฌ๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
} else {
  // ๋ฏธ์„ฑ๋…„์ž„์„ ์•Œ๋ฆฌ๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
} // bad 
boolean isAdult = user.getAge() >= 19;

if (isAdult) {
  // ์„ฑ์ธ์ž„์„ ์•Œ๋ฆฌ๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
} else {
  // ๋ฏธ์„ฑ๋…„์ž„์„ ์•Œ๋ฆฌ๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
} // good 

1. ๊ทธ๋ฆ‡๋œ ์ •๋ณด๋ฅผ ํ”ผํ•ด๋ผ.

์˜๋ฌธ์ž O์™€ ์ˆซ์ž 0 ๊ณผ ๊ฐ™์ด ๊ตฌ๋ถ„์ด ์–ด๋ ค์šด ์กฐํ•ฉ์„ ์ •๋ณด๋กœ ์ œ๊ณตํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.

์œ ์‚ฌํ•œ ๊ฐœ๋…์€ ์œ ์‚ฌํ•œ ํ‘œ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜์ง€๋งŒ(์ผ๊ด€์„ฑ) ๋‹ค๋ฅธ ๊ฐœ๋…๊ณผ ํ˜ผ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

2. ์˜๋ฏธ์žˆ๊ฒŒ ๊ตฌ๋ถ„ํ•˜๋ผ.

๋ฌธ์ž์—ด์„ ์นดํ”ผํ•  ๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ (char a1[], char a2[]) ๋ณด๋‹ค๋Š” (char source[], char destination[]) ์ด ํ›จ์”ฌ ์ฝ๊ธฐ ํŽธํ•˜๋‹ค.

3. ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์‰ฌ์šด ์ด๋ฆ„, ๋ฐœ์Œํ•˜๊ธฐ ์‰ฌ์šด ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ผ.

4. ํด๋ž˜์Šค ์ด๋ฆ„ ๊ทœ์น™

ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ๊ฐ์ฒด ์ด๋ฆ„์€ ๋ช…์‚ฌ๋‚˜ ๋ช…์‚ฌ๊ตฌ๊ฐ€ ์ ํ•ฉํ•˜๋‹ค.

ex)Customer, Account ๋“ฑ (info, data, manager ๋“ฑ์€ ํ”ผํ•œ๋‹ค)

5. ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๊ทœ์น™

๋™์‚ฌ๋‚˜ ๋™์‚ฌ๊ตฌ๊ฐ€ ์ ํ•ฉํ•˜๋‹ค.

ex) registerUser, deletePage

6. ํ•œ ๊ฐœ๋…์— ํ•œ ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ผ.

ex) fetch, get, retrieve๋“ฑ๊ณผ ๊ฐ™์ด ํ•œ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์—ฌ๋Ÿฌ ํ‘œ๊ธฐ๋‚˜ ์—ฌ๋Ÿฌ ๋‹จ์–ด๋Š” ํ”ผํ•˜๋ผ.

ํ•จ์ˆ˜ (๋ฉ”์„œ๋“œ)

  • ํ•จ์ˆ˜๋Š” ์ž‘๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
  • ํ•œ๊ฐ€์ง€๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
  • ํ•จ์ˆ˜๋‹น ํ•˜๋‚˜์˜ ์ถ”์ƒํ™” ์ˆ˜์ค€์„ ์œ ์ง€ํ•œ๋‹ค.
  • ์œ„์—์„œ ์•„๋ž˜๋กœ ์ฝ”๋“œ ์ฝ๊ธฐ : ๋‚ด๋ ค๊ฐ€๊ธฐ ๊ทœ์น™, ์œ„์—์„œ ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ์ฝ”๋“œ๊ฐ€ ์ด๋™๋˜์–ด์•ผ ํ•œ๋‹ค.
    • ๊ฐœ์ธ์ ์ธ ์˜๊ฒฌ์ด์ง€๋งŒ ํ•œ ๋ฉ”์„œ๋“œ์— ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋“ค์ด ์กด์žฌํ•œ๋‹ค๋ฉด ๋จผ์ € ์ฝํžˆ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ”๋กœ ๋ฐ‘์— ์กด์žฌํ•˜๋Š”๊ฒŒ ์ฝ๊ธฐ ํŽธํ•˜๋‹ค.

1. switch ๋ฌธ

switch ๋ฌธ์€ ๊ธฐ๋ณธ์ ์ธ ๋ถ„๊ธฐ ๋ฌธ๋ฒ•์ด ๊ธธ์–ด ์ž‘๊ฒŒ ๋งŒ๋“ค๊ธฐ ์–ด๋ ต๋‹ค.
๋˜ํ•œ ๊ธฐ๋Šฅ์ƒ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์กฐ๊ฑด์— ๋งž๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ์ด๋ฅผ ์ €์ฐจ์› ํด๋ž˜์Šค๋กœ ์ˆจ๊ธฐ๊ณ  ๋ณ€๊ฒฝ๋˜๋Š” ์š”์ธ์— ๋”ฐ๋ฅธ ์˜ํ–ฅ๋„๋ฅผ ์ตœ์†Œํ™” ํ•ด์•ผ ํ•œ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž. ๊ฐ ๊ทผ๋ฌดํ˜•ํƒœ์— ๋”ฐ๋ฅธ ๊ธ‰์—ฌ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋กœ์ง์ด๋‹ค.

/**
 * @author CodeVillains
 * @description ์ง๊ด€์ ์œผ๋กœ switch ์กฐ๊ฑด์‹์„ ํ†ตํ•ด ์ž‘์„ฑํ•œ ๊ธ‰์—ฌ ๊ณ„์‚ฐ ๋กœ์ง.   
 * ์žฅ์  : switch ๊ตฌ๋ฌธ์„ ์ด์šฉํ•ด์„œ ๋กœ์ง์„ ์ง๊ด€์ ์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ์ˆœํ•œ ๋กœ์ง์˜ ๊ฒฝ์šฐ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ดˆ๋ณด์ž์šฉ ์ฝ”๋“œ๋กœ ์ ํ•ฉํ•˜๋‹ค. 
 * ๋‹จ์  : ์ฝ”๋“œ ์ค‘๋ณต - switch ๋ฌธ ๋‚ด์˜ ๊ฐ ์‚ฌ๋ก€๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ณ„์‚ฐ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์ผ์ • ์ˆ˜์ค€์˜ ์ฝ”๋“œ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•œ๋‹ค. 
 * OCP ์œ„๋ฐ˜ - ์ง์› ์œ ํ˜•์ด ์ถ”๊ฐ€๋œ๋‹ค๊ฑฐ๋‚˜ ๊ธ‰์—ฌ ๊ณ„์‚ฐ์‹์ด ๋ฐ”๋€” ๊ฒฝ์šฐ ์Šค์œ„์น˜ ๊ตฌ๋ฌธ๋‚ด๋ถ€๊ฐ€ ๊ธ‰๊ฒฉํ•˜๊ฒŒ ๋Š˜์–ด๋‚˜๊ณ  ๊ฐ๊ฐ์˜ ์ฝ”๋“œ ๋กœ์ง์ด ๋ณต์žกํ•ด์ ธ ์œ ์ง€๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ต๋‹ค.(๊ฐœ๋ฐฉํ์‡„ ์›์น™ ์œ„๋ฐ˜)
 */
public class EmployeePaySwitch {
    
    public static void main(String[] args) {
        String employeeType = "Contract"; // ์ง์› ์œ ํ˜• ์„ค์ •
        double hoursWorked = 40; // ๊ทผ๋ฌด ์‹œ๊ฐ„
        double hourlyRate = 15000; // ์‹œ๊ฐ„๋‹น ๊ธ‰์—ฌ

        double pay = calculatePay(employeeType, hoursWorked, hourlyRate);
        System.out.println("์ง์› ์œ ํ˜•: " + employeeType);
        System.out.println("๊ทผ๋ฌด ์‹œ๊ฐ„: " + hoursWorked + "์‹œ๊ฐ„");
        System.out.println("์‹œ๊ฐ„๋‹น ๊ธ‰์—ฌ: " + hourlyRate + "์›");
        System.out.println("์ด ๊ธ‰์—ฌ: " + pay + "์›");
    }

    public static double calculatePay(String employeeType, double hoursWorked, double hourlyRate) {
        double pay = 0;

        switch (employeeType) {
            case "Regular":
                pay = hoursWorked * hourlyRate + 50000; // ์ •๊ทœ์ง ์ถ”๊ฐ€ ๊ธ‰์—ฌ
                break;
            case "Contract":
                pay = hoursWorked * hourlyRate;
                break;
            case "Temporary":
                pay = hoursWorked * hourlyRate * 0.8; // ์ž„์‹œ์ง ๊ธ‰์—ฌ์œจ
                break;
            case "Asist":
                pay = hoursWorked * hourlyRate * 0.7; // ์–ด์‹œ์ŠคํŠธ ๊ธ‰์—ฌ์œจ
                break;
            default:
                System.out.println("์œ ํšจํ•˜์ง€ ์•Š์€ ์ง์› ์œ ํ˜•์ž…๋‹ˆ๋‹ค.");
        }
        return pay;
    }
}

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด ์ฝ”๋“œ์—์„œ ์ข€ ๋” ๊ฐœ์„ ํ•ด๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•  ๊ฒƒ์ด๋‹ค.

public class EmployeePaySwitchRefactor {

    public static void main(String[] args) {
        String employeeType = "Contract"; // ์ง์› ์œ ํ˜• ์„ค์ •
        double hoursWorked = 40; // ๊ทผ๋ฌด ์‹œ๊ฐ„
        double hourlyRate = 15000; // ์‹œ๊ฐ„๋‹น ๊ธ‰์—ฌ

        double pay = calculatePay(employeeType, hoursWorked, hourlyRate);
        System.out.println("์ง์› ์œ ํ˜•: " + employeeType);
        System.out.println("๊ทผ๋ฌด ์‹œ๊ฐ„: " + hoursWorked + "์‹œ๊ฐ„");
        System.out.println("์‹œ๊ฐ„๋‹น ๊ธ‰์—ฌ: " + hourlyRate + "์›");
        System.out.println("์ด ๊ธ‰์—ฌ: " + pay + "์›");
    }

    public static double calculatePay(String employeeType, double hoursWorked, double hourlyRate) {
        double pay = 0;

        switch (employeeType) {
            case "Regular":
                pay = calculatePayWithAdjustment(hoursWorked, hourlyRate, 1.0); // ์ •๊ทœ์ง ์ถ”๊ฐ€ ๊ธ‰์—ฌ
                break;
            case "Contract":
                pay = calculatePayWithAdjustment(hoursWorked, hourlyRate, 1.0);
                break;
            case "Temporary":
                pay = calculatePayWithAdjustment(hoursWorked, hourlyRate, 0.8); // ์ž„์‹œ์ง ๊ธ‰์—ฌ์œจ
                break;
            case "Assist":
                pay = calculatePayWithAdjustment(hoursWorked, hourlyRate, 0.7); // ์–ด์‹œ์ŠคํŠธ ๊ธ‰์—ฌ์œจ
                break;
            default:
                System.out.println("์œ ํšจํ•˜์ง€ ์•Š์€ ์ง์› ์œ ํ˜•์ž…๋‹ˆ๋‹ค.");
        }

        return pay;
    }

    private static double calculatePayWithAdjustment(double hoursWorked, double hourlyRate, double adjustment) {
        return hoursWorked * hourlyRate * adjustment;
    }
}

switch ๊ตฌ๋ฌธ ๋‚ด์—์„œ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๋Š” ๋ถ€๋ถ„์„ ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค.

์žฅ์ ์œผ๋กœ๋Š” ๊ณตํ†ต ๊ธ‰์—ฌ ๊ณ„์‚ฐ ๋กœ์ง์„ ๋ณ„๋„์˜ ๋ฉ”์„œ๋“œ๋กœ ์ถ”์ถœํ•˜๋ฉด ์ค‘๋ณต์ด ์ค„์–ด๋“ค๊ณ  ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ์ข‹์•„์กŒ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ฐ ๊ณ„์‚ฐ ๋กœ์ง์ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝ ๋˜์–ด ๊ฐ€๋…์„ฑ ๋ฐ ๋ณ€๊ฒฝ ์˜ํ–ฅ๋„๊ฐ€ ์ค„์–ด๋“ค์–ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๋” ์‰ฝ๋‹ค๋Š” ๊ฒƒ์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์•„์ง switch ๋ฌธ์— ๋กœ์ง์ด ์กด์žฌํ•˜์—ฌ ๊ทผ๋ฌด ํ˜•ํƒœ์•  ๋”ฐ๋ฅธ ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋˜๋ฉด ๋‚ด๋ถ€ ๋กœ์ง์— ์ˆ˜์ •์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๊ณ (OCP) switch ๋ฌธ์ด ์ฃผ์š” ํ๋ฆ„์ด๋ฏ€๋กœ ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€ ๋œ๋‹ค๊ฑฐ๋‚˜ ํ•˜๋Š” ๋“ฑ์˜ ํ™•์žฅ์„ฑ์—๋Š” ์™„์ „ํžˆ ์œ ์šฉํ•ด๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ switch ๊ตฌ๋ฌธ์„ ์–ด๋”˜๊ฐ€๋กœ ์œ„์ž„ํ•˜๊ฑฐ๋‚˜ ์ƒ์† ๊ด€๊ณ„๋กœ ์ˆจ๊ฒจ ์‹ค์ œ ๋กœ์ง์„ ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š”๊ฒŒ ๋” OOP์— ์ ํ•ฉํ•˜๋‹ค.

์—ฌ๊ธฐ์„œ ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธ‰์—ฌ ๊ณ„์‚ฐ์€ ๊ตฌํ˜„ํ•˜๋Š” ๋ชจ๋“  ๊ทผ๋ฌดํ˜•ํƒœ ํด๋ž˜์Šค์—์„œ ๊ฐ๊ฐ์˜ ๋กœ์ง์„ ๊ฐ€์ ธ์•ผ ํ•˜๋ฏ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ •์˜ํ•œ๋‹ค.

/**
 * ๊ธ‰์—ฌ ๊ณ„์‚ฐ์— ๋Œ€ํ•œ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
 */
public interface PayCalculator {
    double calculatePay(double hoursWorked, double hourlyRate);
}

์ •๊ทœ์ง์ธ ๊ฒฝ์šฐ ๊ธ‰์—ฌ ๊ณ„์‚ฐ์‹์—์„œ + 50000์ด ์ถ”๊ฐ€๋˜๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ณ„์‚ฐ์‹์ด ๋œ๋‹ค.

public class RegularPayCalculator implements PayCalculator {

    @Override
    public double calculatePay(double hoursWorked, double hourlyRate) {
        return hoursWorked * hourlyRate + 50000;
    }
}

๊ณ„์•ฝ์ง๊ณผ ์ž„์‹œ์ง, ์–ด์‹œ์ŠคํŠธ ๊ณ„์‚ฐ์‹๋„ ๊ฐ๊ฐ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.

// ๊ณ„์•ฝ์ง 
public class ContractPayCalculator implements PayCalculator {
    @Override
    public double calculatePay(double hoursWorked, double hourlyRate) {
        return hoursWorked * hourlyRate;
    }
}
// ์ž„์‹œ์ง 
public class TemporaryPayCalculator implements PayCalculator {
   @Override
   public double calculatePay(double hoursWorked, double hourlyRate) {
      return hoursWorked * hourlyRate * 0.8; // Temporary employe
   }
}
// ์–ด์‹œ์ŠคํŠธ 
class AssistPayCalculator implements PayCalculator {
    @Override
    public double calculatePay(double hoursWorked, double hourlyRate) {
        return hoursWorked * hourlyRate * 0.7; // Assist employee
    }
}

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ๊ตฌ์ฒด์ ์ธ ๊ธ‰์—ฌ ๊ณ„์‚ฐ ํด๋ž˜์Šค๋“ค์ด๋‹ค. ์ด์ œ ์ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ(๋ฉ”์ธ ์ฝ”๋“œ)์™€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

public class PayCalculatorFactory {

    static PayCalculator createPayCalculator(String employeeType) {
        switch (employeeType) {
            case "Regular":
                return new RegularPayCalculator();
            case "Contract":
                return new ContractPayCalculator();
            case "Temporary":
                return new TemporaryPayCalculator();
            case "Assist":
                return new AssistPayCalculator();
            default:
                return null;
        }
    }
}

createPayCalculator ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ ์ ˆํ•œ ๊ธ‰์—ฌ ๊ณ„์‚ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์˜จ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ switch ๊ตฌ๋ฌธ์— ๋”ฐ๋ฅธ ์ง์› ์œ ํ˜•์˜ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

public class EmployeePayAbstractFatoryMain {

    public static void main(String[] args) {
        String employeeType = "Contract"; // Employee type setting
        double hoursWorked = 40; // Hours worked
        double hourlyRate = 15000; // Hourly rate

        PayCalculator payCalculator = PayCalculatorFactory.createPayCalculator(employeeType);
        if (payCalculator != null) {
            double pay = payCalculator.calculatePay(hoursWorked, hourlyRate);
            System.out.println("Employee type: " + employeeType);
            System.out.println("Hours worked: " + hoursWorked + " hours");
            System.out.println("Hourly rate: " + hourlyRate + " won");
            System.out.println("Total pay: " + pay + " won");
        } else {
            System.out.println("Invalid employee type.");
        }
    }
}

์‹ค์ œ ํ˜ธ์ถœ ๋ถ€๋ถ„์€ switch ๊ตฌ๋ฌธ์ด ๋ณด์ด์ง€ ์•Š๊ณ  ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•œ ์ง์› ์œ ํ˜•์— ๋”ฐ๋ฅธ ๊ณ„์‚ฐ์‹์„ ํ˜ธ์ถœ ํ•œ ๋’ค ๊ฒฐ๊ณผ๊ฐ’๋งŒ์„ ์ถœ๋ ฅ(return) ํ•ด์ฃผ๋Š” ์—ญํ• ์ด ๋์ด๋‹ค.

์ด ์ฝ”๋“œ๋Š” ๊ฐ ์ง์› ์œ ํ˜•์— ๋Œ€ํ•œ ๊ธ‰์—ฌ ๊ณ„์‚ฐ์„ ๋ชจ๋“ˆํ™”ํ•˜๊ณ , ์ถ”๊ฐ€์ ์ธ ์ง์› ์œ ํ˜•์ด ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ์ˆ˜์ •์„ ์ตœ์†Œํ™”ํ•œ๋‹ค. ๋ฌผ๋ก  ์ƒˆ๋กœ์šด ์ง์› ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์—ฌ์ „ํžˆ ์Šค์œ„์น˜ ๋ฌธ ๋‚ด์—์„œ ์ƒˆ๋กœ์šด ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ•ด์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— OCP๋ฅผ ์™„์ „ํžˆ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์›๋ณธ ์ฝ”๋“œ์™€ ๋น„๊ตํ•œ๋‹ค๋ฉด ๋” ์œ ์ง€๋ณด์ˆ˜ ํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ธฐ๋Šฅ๋ณ„ ๋ชจ๋“ˆํ™”๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์ฝ”๋“œ์˜ ๋ฐฉํ–ฅ์— ๋งž๊ฒŒ ์„ค๊ณ„๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ํ•ด๋‹น ์ฝ”๋“œ์— switch ๊ตฌ๋ฌธ์„ ์ œ๊ฑฐํ•˜๊ณ  ์ „๋žต ํŒจํ„ด์œผ๋กœ ์ข€ ๋” ์™„๋ฒฝํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์ถ”๊ฐ€ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋“ค์„ ์‚ดํŽด๋ณด๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ด๋‹ค.

https://github.com/villainscode/coding-guide/tree/main/src/main/java/net/mingleup/guide/employee/strategy

๋น„์Šทํ•œ ๊ตฌ์กฐ๋กœ ๋ฆฌํŒฉํ† ๋ง ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

2. ์„œ์ˆ ์ ์ธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ผ.

๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜๋Š” ์ผ์„ ์ข€ ๋” ์ž˜ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„œ์ˆ ํ˜• ์ด๋ฆ„์„ ์ง€์–ด์•ผ ํ•œ๋‹ค.

๋ชจ๋“ˆ ๋‚ด์—์„œ ํ•จ์ˆ˜ ์ด๋ฆ„์€ ์ผ๊ด€์„ฑ(๊ฐ™์€ ๋ฌธ๊ตฌ๋‚˜ ๋ช…์‚ฌ, ๋™์‚ฌ๋“ฑ์˜ ์‚ฌ์šฉ ๊ทœ์น™)์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค.

3. ๋ฉ”์„œ๋“œ ์ธ์ˆ˜

์ด์ƒ์ ์ธ ์ธ์ˆ˜์˜ ๊ฐฏ์ˆ˜๋Š” '์—†์œผ๋ฉด ์—†์„์ˆ˜๋ก ์ข‹๋‹ค' ์ด๋‹ค. ์ธ์ˆ˜๋ฅผ ์ฃผ๋”๋ผ๋„ 3๊ฐœ ์ด์ƒ์€ ์ง€์–‘ํ•˜๊ณ , 4๊ฐœ ๋ถ€ํ„ฐ๋Š” ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค. ๋˜ํ•œ ์ธ์ˆ˜๊ฐ’์œผ๋กœ flag๋ฅผ ๋„˜๊ธฐ๋‹ค๋Š” ๊ฒƒ์€ ๋ฉ”์„œ๋“œ์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋ฏ€๋กœ boolean ์„ ํ†ตํ•ด ๋‚ด๋ถ€์—์„œ ๊ฐ’์„ ์กฐ์ž‘ํ•˜๋Š” ํ–‰์œ„๋Š” ์ง€์–‘ํ•ด์•ผ ํ•œ๋‹ค.

4. ๋ช…๋ น๊ณผ ์กฐํšŒ๋ฅผ ๋ถ„๋ฆฌํ•ด๋ผ.

5. DRY (Don't Repaet Yourself)

6. ์ฃผ์„์€ ์ฝ”๋“œ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ฆ‰, ์ฃผ์„์€ ๋‚˜์œ ์ฝ”๋“œ๋ฅผ ๋ณด์™„ํ•˜์ง€ ๋ชปํ•œ๋‹ค.

Code as Docuementation by Martin fowler

๋‹จ์ˆœ ์ •๋ณด๋งŒ ์ฃผ๋Š” ์ฃผ์„์€ ์•„๋ฌด๋Ÿฐ ๊ฐ€์น˜๊ฐ€ ์—†๊ณ  ์˜คํžˆ๋ ค ์ฝ”๋“œ์˜ ์˜๋„๋งŒ ํ•ด์น˜๊ฒŒ ๋˜๊ณ  ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฏ€๋กœ ํ•„์ˆ˜์ ์ธ ๋‚ด์šฉ๋งŒ์„ ๊ธฐ๋กํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค.

ํ˜•์‹ ๋งž์ถ”๊ธฐ

๋“ค์—ฌ์“ฐ๊ธฐ, ๋นˆ ํ–‰์œผ๋กœ ๊ฐ€์‹œ์„ฑ์„ ํ™•๋ณดํ•˜๊ฑฐ๋‚˜ ์ ์ ˆํ•œ ์ˆ˜์ค€์˜ ํ–‰ ๊ธธ์ด๋ฅผ ๋งž์ถ”๋Š” ๋“ฑ์˜ ๋…ธ๋ ฅ์€ ๊ฒฐ๊ตญ ์ฝ”๋“œ์˜ ํ’ˆ์งˆ๊ณผ ๊ฐ€๋…์„ฑ์— ์ง๊ฒฐ๋œ๋‹ค. 20์ž~60๋ฐ” ์ •๋„์˜ ๊ฐ€๋กœํ–‰์ด ์ ์ ˆํ•˜๊ณ  ๊ทธ๋ณด๋‹ค ๋” ์งง์„ ์ˆ˜๋ก ์ธ์ง€์œจ์ด ์˜ฌ๋ผ๊ฐ„๋‹ค.
๋˜ํ•œ ํŒ€์ด๋ผ๋ฉด ํŒ€ ๋‚ด๋ถ€์—์„œ ๋ช…๋ช…๋ฒ•์ด๋‚˜ ์ฝ”๋”ฉ ๊ทœ์น™์„ ๋งˆ๋ จํ•ด์„œ ์ด ํ˜•์‹์„ ๋”ฐ๋ผ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ์ฒด์™€ ์ž๋ฃŒ ๊ตฌ์กฐ

๋””๋ฏธํ„ฐ์˜ ๋ฒ•์น™ : ์˜ค์ง ํ•˜๋‚˜์˜ ์ (.)์— ์˜ํ•ด ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ๋งŒ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

public class Car {
   private Engine engine;

   public Car(Engine engine) {
      this.engine = engine;
   }

   public Engine getEngine() {
      return engine;
   }
}

public class Engine {
   public void start() {
      // ์—”์ง„์„ ์‹œ์ž‘ํ•˜๋Š” ๋กœ์ง
   }
}

public class Driver {
   public void drive(Car car) {
      // ๋””๋ฏธํ„ฐ์˜ ๋ฒ•์น™ ์œ„๋ฐ˜: Car ๊ฐ์ฒด์—์„œ ์—”์ง„์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•จ
      car.getEngine().start(); // ์—”์ง„์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
   }
}

Driver ํด๋ž˜์Šค์˜ drive ๋ฉ”์„œ๋“œ๋Š” Car ํด๋ž˜์Šค์˜ getEngine์„ ํ†ตํ•ด start ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๋Œ€์‹ ์— Car ํด๋ž˜์Šค ๋‚ด์—์„œ ์—”์ง„์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

public class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void startEngine() {
        engine.start();
    }
}

public class Engine {
    public void start() {
        // ์—”์ง„์„ ์‹œ์ž‘ํ•˜๋Š” ๋กœ์ง
    }
}

public class Driver {
    public void drive(Car car) {
        car.startEngine(); // ๋””๋ฏธํ„ฐ์˜ ๋ฒ•์น™ ์ค€์ˆ˜: Car ํด๋ž˜์Šค์—์„œ ์—”์ง„ ์‹œ์ž‘ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•จ
    }
}

Driver ํด๋ž˜์Šค์—์„œ๋Š” Car ๊ฐ์ฒด์˜ startEngine ๋ฉ”์„œ๋“œ๋งŒ ํ˜ธ์ถœํ•˜์—ฌ ์—”์ง„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋กœ์จ Car ํด๋ž˜์Šค๊ฐ€ ์—”์ง„์— ๋Œ€ํ•œ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์บก์Šํ™”ํ•˜๊ณ  ์™ธ๋ถ€๋กœ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

์ž๋ฃŒ ์ „๋‹ฌ ๊ฐ์ฒด

DTO(Data Transfer Object)๋ฅผ ํ†ตํ•ด ์ „์†กํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•˜๊ณ  ๋ชจ๋“ˆ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถฐ์•ผ ํ•œ๋‹ค.
๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์•„์ง€๊ณ , ์œ ์—ฐ์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์ด ์ €ํ•˜๋œ๋‹ค.
๋˜ํ•œ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ์ ์ ˆํ•œ ์ „๋‹ฌ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ „์†ก์˜ ๋ช…ํ™•์„ฑ๊ณผ ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•˜๊ณ , ์‹œ์Šคํ…œ์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”์–ด ์œ ์ง€ ๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ํ–ฅ์ƒ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

์˜ค๋ฅ˜ ์ฝ”๋“œ๋ณด๋‹ค ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ.

์˜ค๋ฅ˜ ์ฝ”๋“œ ๋Œ€์‹ ์— ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜๊ณ  ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ฐ€ ๋ช…ํ™•ํ•ด์ง€๋ฉฐ, ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ๊ณผ ์•ˆ์ •์„ฑ์ด ํ–ฅ์ƒ๋œ๋‹ค.

public class Calculator {
    public int divide(int dividend, int divisor) {
        if (divisor == 0) {
            return -1; // ์˜ค๋ฅ˜ ์ฝ”๋“œ ๋ฐ˜ํ™˜
        }
        return dividend / divisor;
    }
}

์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๊ฑด์ง€ ๋กœ์ง์—์„œ ๋” ์ด์ƒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ธ์ง€ ํŒ๋‹จํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค.

public class Calculator {
    public int divide(int dividend, int divisor) {
        if (divisor == 0) {
            throw new IllegalArgumentException("Divisor cannot be zero"); // ์˜ˆ์™ธ ๋ฐœ์ƒ
        }
        return dividend / divisor;
    }
}

null์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋งˆ๋ผ.

null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ์ž๊ฐ€ ํ•ด๋‹น ๊ฐ’์ด null์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์•ˆ์ „์„ฑ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ return null ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ์ฃผ์ง€ ๋ง๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

if (user == null) {
   throw new IllegalArgumentException("User not found with username: " + username);
}

ํด๋ž˜์Šค

ํด๋ž˜์Šค ์ž‘์„ฑ ๊ทœ์น™

ํด๋ž˜์Šค ์ฒด๊ณ„์ƒ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ํ‘œ์ค€ ์ž๋ฐ” ๊ทœ์น™์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. ์ƒ์ˆ˜(Constant): ํด๋ž˜์Šค ์ˆ˜์ค€์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ƒ์ˆ˜๋ฅผ ์ •์˜. ์ •์  ๊ณต๊ฐœ ์ƒ์ˆ˜๊ฐ€ ๋งจ ์ฒ˜์Œ ๋‚˜์˜ค๊ณ  ๋‹ค์Œ์œผ๋กœ ์ •์  ๋น„๊ณต๊ฐœ๊ฐ€ ๋‚˜์˜จ๋‹ค.
  2. ๋ฉค๋ฒ„ ๋ณ€์ˆ˜(Fields): ํด๋ž˜์Šค์˜ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ์ •์˜.
  3. ์ƒ์„ฑ์ž(Constructor): ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ •์˜.
  4. ๋ฉ”์„œ๋“œ(Methods): public ๋ฉ”์„œ๋“œ๊ฐ€ ๋‚˜์˜ค๊ณ  ๊ทธ ๋’ค์— private ํ˜ธ์ถœ ๋ฉ”์„œ๋“œ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ž‘์„ฑํ•ด์ค€๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

public class ExampleClass {

    // ์ƒ์ˆ˜
    private static final int MAX_SIZE = 100;
    private static final String DEFAULT_NAME = "Default";

    // ๋ฉค๋ฒ„ ๋ณ€์ˆ˜
    private int size;
    private String name;

    // ์ƒ์„ฑ์ž
    public ExampleClass() {
        this.size = 0;
        this.name = DEFAULT_NAME;
    }

    public ExampleClass(int size, String name) {
        this.size = size;
        this.name = name;
    }

    // ๋ฉ”์„œ๋“œ
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // ์ค‘์ฒฉ ํด๋ž˜์Šค
    private static class NestedClass {
        // ์ค‘์ฒฉ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜, ์ƒ์„ฑ์ž, ๋ฉ”์„œ๋“œ ๋“ฑ
    }
}

ํด๋ž˜์Šค๋Š” ์ž‘๊ฒŒ ์„ค๊ณ„ ํ•ด์•ผํ•œ๋‹ค.

SRP

SRP(Single Responsibility Principle, ๋‹จ์ผ ์ฑ…์ž„ ์›์น™)๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ํด๋ž˜์Šค๋‚˜ ๋ชจ๋“ˆ์€ ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋กœ, ์ด๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋‹จ ํ•˜๋‚˜๋ฟ์ด์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.

public class ReportGenerator {

    public void generateReport() {
        // ๋ณด๊ณ ์„œ ์ƒ์„ฑ ๋กœ์ง
        String data = fetchDataFromDatabase();
        formatData(data);
        saveReportToFile(data);
    }

    private String fetchDataFromDatabase() {
        // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง
        return "Data from database";
    }

    private void formatData(String data) {
        // ๋ฐ์ดํ„ฐ ํฌ๋งทํŒ… ๋กœ์ง
        System.out.println("Formatting data: " + data);
    }

    private void saveReportToFile(String data) {
        // ํŒŒ์ผ์— ๋ณด๊ณ ์„œ๋ฅผ ์ €์žฅํ•˜๋Š” ๋กœ์ง
        System.out.println("Saving report to file: " + data);
    }
}

์ด ์ฝ”๋“œ๋Š” ๋ณด๊ณ ์„œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๊ฐ์ข… ํƒ€์ž…์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ์ด๋Š” SRP ์œ„๋ฐ˜์ด๊ณ  ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ ๋˜์–ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋‹ค์–‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋ž˜์˜ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

public class ReportGenerator {

    private DatabaseFetcher databaseFetcher;
    private DataFormatter dataFormatter;
    private FileSaver fileSaver;

    public ReportGenerator(DatabaseFetcher databaseFetcher, DataFormatter dataFormatter, FileSaver fileSaver) {
        this.databaseFetcher = databaseFetcher;
        this.dataFormatter = dataFormatter;
        this.fileSaver = fileSaver;
    }

    public void generateReport() {
        String data = databaseFetcher.fetchData();
        String formattedData = dataFormatter.formatData(data);
        fileSaver.saveToFile(formattedData);
    }
}
public class DatabaseFetcher {

    public String fetchData() {
        // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง
        return "Data from database";
    }
}
public class DataFormatter {

    public String formatData(String data) {
        // ๋ฐ์ดํ„ฐ ํฌ๋งทํŒ… ๋กœ์ง
        return "Formatted data: " + data;
    }
}
public class FileSaver {

    public void saveToFile(String data) {
        // ํŒŒ์ผ์— ๋ณด๊ณ ์„œ๋ฅผ ์ €์žฅํ•˜๋Š” ๋กœ์ง
        System.out.println("Saving report to file: " + data);
    }
}

ReportGenerator ํด๋ž˜์Šค๊ฐ€ ๋ณด๊ณ ์„œ ์ƒ์„ฑ๋งŒ ๋‹ด๋‹นํ•˜๋„๋ก ๋ณ€๊ฒฝ๋˜์—ˆ๊ณ  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ(DatabaseFetcher), ๋ฐ์ดํ„ฐ ํฌ๋งทํŒ…(DataFormatter), ํŒŒ์ผ ์ €์žฅ(FileSaver) ๋“ฑ์˜ ์—ญํ• ์€ ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌ๋˜์—ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ ํด๋ž˜์Šค๋Š” ๋‹จ์ผ ์ฑ…์ž„์„ ๊ฐ–๊ฒŒ ๋˜๊ณ , ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ํ•ด๋‹น ํด๋ž˜์Šค๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•ด์ง„๋‹ค.

์‘์ง‘๋„(Cohesion)

์‘์ง‘๋„๊ฐ€ ๋†’์€ ์ฝ”๋“œ๋Š” ๊ฐ€๊ธ‰์  ์ž‘๊ฒŒ ๋‚˜๋ˆ ์„œ ์‘์ง‘๋„๋ฅผ ๋‚ฎ์ถฐ์•ผ ํ•œ๋‹ค. ๋‹จ, ํ•œ๊ฐ€์ง€ ๊ธฐ๋Šฅ๋งŒ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์ด๋ผ๋ฉด ์ƒ๊ด€์—†๋‹ค.

์ฝ”๋“œ ๊ธฐ๋ณธ ์‚ฌ์šฉ ๊ทœ์น™ ๋ชจ์Œ


์šฉ๋ก€๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์ „์— ์•Œ์•„๋‘ฌ์•ผ ํ•  ๊ฒƒ

ํ•˜๋‚˜์˜ ์ฝ”๋“œ ๋ธ”๋Ÿญ์œผ๋กœ ํ‘œํ˜„ํ•œ ๋ถ€๋ถ„์€ ์ƒ๋‹จ ์„ค๋ช…์— ๋Œ€ํ•œ ์ฝ”๋“œ ์ƒ˜ํ”Œ์ด๋‹ค.

์ƒ๋‹จ ์„ค๋ช…์€ Bold๋กœ ํ‘œ๊ธฐ ํ•˜์˜€๋‹ค.

์ฝ”๋“œ๋ฅผ ๋น„๊ตํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์€ ์œ„์™€ ์•„๋ž˜๋กœ ๋‚˜๋ˆ  ์œ„๋Š” BadCase, ์•„๋ž˜๋Š” GoodCase๋กœ ๊ธฐ์ˆ ํ•˜์˜€๋‹ค.

๊ทœ์น™ 1. ํŒŒ์ผ์€ UTF-8๋กœ ์ธ์ฝ”๋”ฉ ํ•œ๋‹ค.

import ๊ตฌ๋ฌธ์€ ์ค„ ๋ฐ”๊ฟˆ ํ•˜์ง€ ์•Š๋Š”๋‹ค. (ํ•œ ์ค„์— ์ „์ฒด๋ฅผ ๊ธฐ์ˆ ํ•œ๋‹ค.)

๊ทœ์น™ 2. ํŒจํ‚ค์ง€ ์ด๋ฆ„์€ ์†Œ๋ฌธ์ž์ด๊ณ , ์–ธ๋”๋ผ์ธ์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

ํŒจํ‚ค์ง€ ๊ตฌ์กฐ๋Š” ์ตœ์ƒ์œ„ ๋„๋ฉ”์ธ๋ถ€ํ„ฐ ์—ญ์ˆœ์œผ๋กœ ํ‘œ๊ธฐํ•˜๋Š”๊ฒƒ์ด ์ปจ๋ฒค์…˜์ด๋‹ค.

 com.company.project

๊ทœ์น™ 3. ํด๋ž˜์Šค ์ด๋ฆ„์€ UpperCamelCase (PascalCase) ๋กœ ์ž‘์„ฑํ•œ๋‹ค. ๋‹จ์–ด์™€ ๋‹จ์–ด ์‚ฌ์ด์—๋Š” ๋Œ€๋ฌธ์ž๋กœ ํ‘œ๊ธฐํ•˜๊ณ  ๋ช…์‚ฌ๋กœ ๋ช…๋ช…ํ•œ๋‹ค.

์•ฝ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋„ ๋™์ผํ•˜๋‹ค.

CustomerController # ํด๋ž˜์Šค
CustomerService # ํด๋ž˜์Šค 
Runnable # ์ธํ„ฐํŽ˜์ด์Šค

๊ทœ์น™ 4 .๋ฉ”์†Œ๋“œ ์ด๋ฆ„์€ lowerCamelCase ๋กœ ์ž‘์„ฑํ•œ๋‹ค. ๋ฉ”์†Œ๋“œ๋ช…์€ ๋™์‚ฌ ๋˜๋Š” ๋™์‚ฌ๊ตฌ์ด๋‹ค.

๋„ค์ด๋ฐ์€ ๋™์‚ฌ๋‚˜ ๋™์‚ฌ๊ตฌ๋กœ ์ง“๊ณ , boolean ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” is๋‚˜ has๋กœ ์‹œ์ž‘ํ•˜๊ณ  ํ˜•์šฉ์‚ฌ๋กœ ๊ธฐ๋Šฅํ•˜๋Š” ๋‹จ์–ด๋กœ ๋๋‚œ๋‹ค.

๊ฐ์ฒด์˜ ํƒ€์ž…์„ ๋ฐ”๊ฟ”์„œ, ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์€ ๋ณดํ†ต toType ํ˜•ํƒœ๋กœ ์ง“๋Š”๋‹ค.(toString, toArray)

getName()
isEmpty()
hasLevel()
toString()

๊ทœ์น™ 5. ๋„ˆ๋ฌด ์งง์€ ๋ณ€์ˆ˜๋ช…, ๋ฉ”์†Œ๋“œ๋ช…์€ ์ง€์–‘ํ•˜๊ณ  ์˜๋ฏธ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ์ง€์–ด์•ผ ํ•œ๋‹ค. ๋ฉ”์†Œ๋“œ ๋ช…์ด๋‚˜ ๋ณ€์ˆ˜๋ช…์€ ์˜๋ฏธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์šฉ๋„๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

๊ทœ์น™ 6. ์ƒ์ˆ˜๋Š” CONST_CASE ์ด๋‹ค. (UPPER_SNAKE_CASE)

  • ์ƒ์ˆ˜๋Š” ๋‚ด์šฉ์ด ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ ํ•ด์•ผ ํ•œ๋‹ค.
  • static final ํ•„๋“œ์ด์–ด์•ผ ํ•œ๋‹ค.
๐Ÿ’ก ์˜ˆ์™ธ์‚ฌํ•ญ - ์ƒ์ˆ˜๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์˜ final (์‹ฑ๊ธ€ํ†ค ๋“ฑ)์€ CamelCase๋กœ ์ž‘์„ฑํ•œ๋‹ค.

๊ทœ์น™ 7. ์ƒ์ˆ˜๊ฐ€ ์•„๋‹Œ ํ•„๋“œ๋Š” lowerCamelCase๋กœ ์ž‘์„ฑํ•œ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์€ lowerCamelCase๋กœ ์ž‘์„ฑํ•œ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ 4๊ฐœ๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ Object ํƒ€์ž…์œผ๋กœ ์ •์˜ํ•˜๋Š”๊ฒŒ OCP(Open-Closed Principle) ์„ค๊ณ„์— ๋งž๋Š” ๋™์ž‘ ๋ฐฉ์‹์ด๋‹ค.

์ง€์—ญ๋ณ€์ˆ˜ ์ด๋ฆ„์€ lowerCamelCase๋กœ ์ž‘์„ฑํ•œ๋‹ค. ๋ณ€์ˆ˜ ์ด๋ฆ„์€ ์งง์ง€๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๊ณ , ์–ธ๋”์Šค์ฝ”์–ด๋‚˜ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์“ฐ๋ฉด ์•ˆ๋œ๋‹ค.

์ƒ์ˆ˜๋Š” static final ํ‚ค์›Œ๋“œ๋กœ ์ •์˜๋œ ํ•„๋“œ์ด๋‹ค. ์ด ํ•„๋“œ์˜ ๋‚ด์šฉ์€ ๋ถˆ๋ณ€ํ•˜๋ฉฐ, ๋ฉ”์†Œ๋“œ๋Š” ๋ถ€์ž‘์šฉ์ด ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค. ์ด๋Š” ์›์‹œ ์ž๋ฃŒํ˜•, String, ๋ถˆ๋ณ€ ํƒ€์ž…, ๋ถˆ๋ณ€ ํƒ€์ž…์˜ ๋ถˆ๋ณ€ collection์„ ํฌํ•จํ•œ๋‹ค. ๋งŒ์•ฝ ์–ด๋–ค ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด๋Š” ์ƒ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.

// ์ƒ์ˆ˜
static final int NUMBER = 5;
static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
static final ImmutableMap<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
static final Joiner COMMA_JOINER = Joiner.on(','); // Joiner๋Š” ๋ถˆ๋ณ€์ด๊ธฐ ๋•Œ๋ฌธ์—.
static final SomeMutableType[] EMPTY_ARRAY = {};
enum SomeEnum { ENUM_CONSTANT }

// ์ƒ์ˆ˜ ์•„๋‹˜
static String nonFinal = "non-final"; // final ์—†์Œ
final String nonStatic = "non-static"; // static ์•„๋‹˜
static final Set<String> mutableCollection = new HashSet<String>(); // ๊ฐ€๋ณ€ํƒ€์ž… String ์‚ฌ์šฉ
static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable); // ๊ฐ€๋ณ€ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋กœ ์ดˆ๊ธฐํ™” ํ•จ
static final ImmutableMap<String, SomeMutableType> mutableValues =
    ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2); // ๊ฐ€๋ณ€ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋กœ ์ดˆ๊ธฐํ™” ํ•จ
static final Logger logger = Logger.getLogger(MyClass.getName());
static final String[] nonEmptyArray = {"these", "can", "change"};

๊ทœ์น™ 8. ๋ณ€์ˆ˜๋Š” lowerCamelCase๋กœ ์ž‘์„ฑํ•œ๋‹ค.

๋‹จ, ๋ณ€์ˆ˜์—์„œ boolean ํƒ€์ž…์„ ์ •์˜ ํ•  ๊ฒฝ์šฐ ๋ฉ”์†Œ๋“œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ isXXX ์™€ ๊ฐ™์€ ์ด๋ฆ„์€ ํ”ผํ•˜๋„๋ก ํ•œ๋‹ค. ์ผ๋ถ€ ์ง๋ ฌํ™” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž„์‹œ ๋ณ€์ˆ˜ (๋ฐ˜๋ณต๋ฌธ์„ ์ˆœํšŒํ•˜๋Š” ๊ฒฝ์šฐ) ๋ผ๋„ ๊ฐ€๊ธ‰์  ํ•œ๊ธ€์ž์˜ ๋ณ€์ˆ˜๋ช… ๋ณด๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ์ง“๋Š”๊ฒƒ์ด ๋‚ซ๋‹ค.

Usage (์ฝ”๋“œ ์˜ˆ์ œ ๋ชจ์Œ)


1. ๊ด„ํ˜ธ๋Š” Egyptian brackets ์„ ๋”ฐ๋ฅธ๋‹ค.

return () -> {
  while (condition()) {
    method();
  }
};

return new MyClass() {
  @Override public void method() {
    if (condition()) {
      try {
        something();
      } catch (ProblemException e) {
        recover();
      }
    } else if (otherCondition()) {
      somethingElse();
    } else {
      lastThing();
    }
  }
};

2. ๋นˆ ๋ธ”๋Ÿญ์ด๋‚˜ block-like construct ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋ฉ€ํ‹ฐ ๋ธ”๋Ÿญ์— ์„ž์–ด์„œ ์‚ฌ์šฉํ• ์ˆœ ์—†๋‹ค.

// ๊ฐ€๋Šฅ
void doNothing() {}

// ๊ฐ€๋Šฅ
void doNothingElse() {
}
// ๋ถˆ๊ฐ€๋Šฅ : multi-block ์—์„œ ๊ด„ํ˜ธ์˜ ์ค„๋ฐ”๊ฟˆ๊ณผ ๋นˆ ๋ธ”๋Ÿญ์„ ๋™์‹œ์— ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ฒƒ 
try {
  doSomething();
} catch (Exception e) {}

3. ๊ณต๋ฐฑ๊ณผ ๋นˆ์ค„

  • ๋“ค์—ฌ์“ฐ๊ธฐ (Indentation)์€ 4์นธ์˜ ๊ณต๋ฐฑ์ด์–ด์•ผ ํ•œ๋‹ค. (4 spaces key)
  • โ€œifโ€, โ€œwhileโ€, โ€œreturnโ€, โ€œcatchโ€, โ€œswitchโ€, โ€œforโ€ ๋“ฑ์˜ ํ‚ค์›Œ๋“œ์™€ ์ด์–ด์ง€๋Š” ๊ด„ํ˜ธ์—๋Š” ๊ณต๋ฐฑ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ์„ธ๋ฏธ์ฝœ๋ก , ์‰ผํ‘œ ๋’ค์—๋Š” ๊ณต๋ฐฑ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ์ฝ”๋“œ์˜ ์ฃผ์š” ๋ถ€๋ถ„์„ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋นˆ ์ค„์„ ๋„ฃ์–ด์ค€๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ณ€์ˆ˜ ์„ ์–ธ ๋ถ€๋ถ„๊ณผ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋กœ์ง์ด ๋“ค์–ด๊ฐ„๋‹ค๋ฉด ์ด ๋ถ€๋ถ„์€ ๊ตฌ๋ถ„์„ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ๋นˆ ์ค„์„ ์‚ฝ์ž…ํ•ด์ฃผ๋Š”๊ฒƒ์ด ์ข‹๋‹ค.

4. Static Factory Method ์˜ ๊ด€ํ–‰์ ์ธ ๋ช…๋ช…

  • from: ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ํ•ด๋‹น ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ (ํ˜•๋ณ€ํ™˜)
  • valueOf : ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜
  • of: ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ (aggregate)
  • instance or getInstance: (๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›๋Š”๋‹ค๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ช…์‹œํ•œ ) ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์ž„์„ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋ณดํ†ต singleton์„ ๊ตฌํ˜„ํ• ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋„ค์ด๋ฐ์ด์ง€๋งŒ ์‹ฑ๊ธ€ํ†ค์˜ ๊ฒฝ์šฐ getInstance๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • create or newInstance: getInstance ์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • getType: getInstance์™€ ๊ฐ™์œผ๋‚˜ ํ˜ธ์ถœํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ• ๋•Œ ์‚ฌ์šฉ
  • newType โ€” newInstance์™€ ๋น„์Šทํ•˜์ง€๋งŒ ํ˜ธ์ถœํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šฌ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ. Type์€ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด์˜ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

5. List ํƒ€์ž…์—์„œ ๋นˆ ์ปฌ๋ ‰์…˜์„ ๋ฐ˜ํ™˜ํ• ๋•Œ๋Š” null์ด๋‚˜ new ์ƒ์„ฑ ๋ฆฌ์ŠคํŠธ ํƒ€์ž… ๋ณด๋‹ค๋Š” Empty Collection์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด GC์— ์œ ๋ฆฌํ•˜๋‹ค.

List<Integer> list = new ArrayList();
Set<Integer> set = new HashSet();
Map<Integer,Integer> map = new HashMap();
List<Integer> list = Collections.emptyList();
Set<Integer> set = Collections.emptySet();
Map<Integer,Integer> map = Collections.emptyMap()

6. foreach ๋ฃจํ”„์—์„œ ์ฝœ๋ ‰์…˜์˜ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜์ง€ ๋ง๊ฒƒ

  • Iterator ๋ฅผ ํ†ตํ•ด ์š”์†Œ๋ฅผ ์กฐ์ž‘ํ•˜๋„๋ก ํ•œ๋‹ค.
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
    if ("2".equals(temp)){
        a.remove(temp);
    }
} // bad 
Iterator<String> it = a.iterator();
while (it.hasNext()) {    
    String temp =  it.next();             
    if (delete condition) {              
        it.remove();       
    }
} // good 

7. Key, Value ์ฝœ๋ ‰์…˜์—์„œ null์ด ์ €์žฅ๋˜๋Š”์ง€ ์ฒดํฌํ•ด๋‘์–ด์•ผ ํ•œ๋‹ค.

Collection Key Value Super Note
Hashtable Null is not allowed Null is not allowed Dictionary Thread-safe
ConcurrentHashMap Null is not allowed Null is not allowed AbstractMap Segment lock
TreeMap Null is not allowed Null is allowed AbstractMap Thread-unsafe
HashMap Null is allowed Null is allowed AbstractMap Thread-unsafe

8. Thread

์˜๋ฏธ ์žˆ๋Š” ์Šค๋ ˆ๋“œ ์ด๋ฆ„์€ ์˜ค๋ฅ˜ ์ •๋ณด๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฏ€๋กœ ์Šค๋ ˆ๋“œ ๋˜๋Š” ์Šค๋ ˆ๋“œ ํ’€์„ ์ƒ์„ฑํ•  ๋•Œ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ธฐ๋ฅผ ์ถ”์ฒœํ•œ๋‹ค.

public class TimerTaskThread extends Thread {
    public TimerTaskThread() {
        super.setName("TimerTaskThread"); 
        ...
    }
}

์Šค๋ ˆ๋“œ๋Š” ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์ œ๊ณต๋˜์–ด์•ผ ํ•œ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ์Šค๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ๋ฐ ์†Œ๋ฉธ ์‹œ๊ฐ„์„ ์ค„์ด๊ณ  ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์Šค๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์œ ์‚ฌํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋งŽ์ด ์ƒ์„ฑ๋˜์–ด "๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ" ๋˜๋Š” ์˜ค๋ฒ„ ์Šค์œ„์นญ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

9. String ํƒ€์ž…์— ์ ์ ˆํ•˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ๊ธฐํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค.

String value = โ€œTrueโ€; // bad
boolean value = true; // good 

10. String์˜ ์ดˆ๊ธฐํ™”์—๋Š” StringUtils.EMPTY์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

String value = โ€œโ€; // bad 
String value = StringUtils.EMPTY; // good 

11. ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ์€ ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž.

public class BadExample {
    public void foo() {
        boolean flag = false;
        if (flag == true) { // bad 
            // some code
        } else {
            // some code
        }
    }
}
public class GoodExample {
    public void foo() {
        boolean flag = false;
        if (flag) { // good 
            // some code
        } else {
            // some code
        }
    }
}

12. Optional ์‚ฌ์šฉ

Exception ํ˜น์€ null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” method์—๋Š” Optional์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • Optional ๊ฐ’์€ postfix๋กœ Optional์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • Exception์€ ์ •๋ง Exception์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉํ•œ๋‹ค. ์ •์ƒ์ ์ธ ํ๋ฆ„์„ ํ†ต์ œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Exception ๋ณด๋‹ค๋Š” Optional์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • Optional์€ null์„ ๋ฐ˜ํ™˜๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์‹œํ•œ๋‹ค.
  • Collection์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” Optional์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
public ExportService getExportRequest() {
    ...
    ExportService exportInfo = getExportRequest();
    if(exportInfo == null){ // bad 
        ...
    }
}
public Optional<ExportService> getExportRequest(){
    ...
    Optional<ExportService> exportInfoOptional = getExportRequest();
    if(exportInfoOptional.isEmpty()){
        // handling the null
    }
    ExportService exportInfo = exportInfoOptional.get();
}

13. Predicate๊ณผ Valdator ๊ตฌ๋ถ„ํ•ด์„œ ์‚ฌ์šฉ

Predicate ์™€ Validator ์˜ ์šฉ๋„๊ฐ€ ๋‹ค๋ฅด๋‹ค.

Predicate

Validator

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ •๋ฆฌํ•˜๋ฉด

Predicate๋Š” 1๊ฐœ์˜ arg ์„ ๋ฐ›์•„์„œ true/false ๋ฆฌํ„ดํ•˜๋Š” ์šฉ๋„์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

Validator๋Š” ๋ฐ์ดํƒ€ ์œ ํšจ์„ฑ์„ ํŒ๋‹จํ•˜๋Š” ์šฉ๋„์œผ๋กœ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ์„œ exception ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

14. ๋ณ€์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ํด๋ž˜์Šค ๊ตฌ์กฐ๋Š” ๋ณ„๋„์˜ ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌํ•˜์ž.

public class BadExample { //bad 
    private int x;
    private int y;
    private int z;
    private int w;

    public void foo() {
        // some code
    }
}
public class GoodExample { // good 
    private Point position;

    public void move(int x, int y) {
        // some code
    }
}

15. ๊ฐ€๊ธ‰์  ์˜ˆ์™ธ๋ฅผ ๊ตฌ์ฒดํ™” ํ•œ๋‹ค.

public class BadExample {
    public void foo() {
        try {
            // some code
        } catch (Exception e) {
            // some code
        }
    }
}
public class GoodExample {
    public void foo() throws SpecificException {
        // some code
    }
}

16. ์งง์€ try ~ catch ๋ธ”๋Ÿญ ๊ถŒ์žฅ

๊ฐ€๋…์„ฑ๋ฉด์—์„œ try catch ๋ธ”๋ก์€ ์งง์•„์•ผ ํ•˜๋ฉฐ, ๊ฐ€๊ธ‰์  exception ๋ธ”๋Ÿญ๋งŒ ์ฒ˜๋ฆฌํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ํ™•๋ณดํ•ด์•ผ ํ•œ๋‹ค.

void tryCatchBlock() { // bad 
    try {
        statement1;
        statement2;
        statement3;    // can throw
        statement4;
    } catch (...) {
        โ€ฆ. 
    }
}
void tryCatchBlock() { // good 
    statement1;
    statement2;
    boolean success = false;
    try {
        statement3;    // can throw
        success = true;
    } catch (...) {
        โ€ฆ  
    }
   
    if (success) {
        statement4;
    }
}

์ด์— ๋Œ€ํ•œ ์„ค๋ช…์œผ๋กœ๋Š” ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

tight try catch block (https://stackoverflow.com/questions/2633834/should-java-try-blocks-be-scoped-as-tightly-as-possible)

the size of a try block makes no difference in performance. Performance is affected by actually raising exceptions at runtime, and that's independent of the size of the try block.

However, keeping try blocks small can lead to better programs.

You might catch exceptions to recover and proceed, or you might catch them simply to report them to the caller (or to a human, via some UI).

In the first case, failures from which you can recover are often very specific, and this leads to smaller try blocks.

In the second case, where an exception is caught so that it can be wrapped by another exception and re-thrown, or displayed to the user, small try blocks mean that you know more precisely which operation failed, and the higher-level context in which that call was made. This allows you to create more specific error reports.

17. SpringFramework ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ž์ฒด Util ๋“ค์€ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

  • ์ด๋Š” SpringFramework ๋‚ด๋ถ€์—์„œ ์“ฐ๊ณ ์ž ๋งŒ๋“ ๊ฒƒ์œผ๋กœ, ๋งŒ์•ฝ Utils์„ฑ๊ฒฉ์˜ ํด๋ž˜์Šค๋ฅผ ์“ฐ๊ณ  ์‹ถ๋‹ค๋ฉด Apache Commons StringUtils๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

18. Spring Annotation์˜ ์ ์ ˆํ•œ ์‚ฌ์šฉ

  • @Component๋Š” ์ผ๋ฐ˜์ ์ธ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ(๊ด€๋ฆฌํ•˜๋Š”) ์ปดํฌ๋„ŒํŠธ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • @Service @Controller, @Repository ๋“ฑ์€ Component ์ž„๊ณผ ๋™์‹œ์— ์„ธ๋ถ€์ ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ช…์‹œ๋ฅผ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.
  • @Controller๋Š” Presentation Layer๋ฅผ ๋‹ด๋‹นํ•˜๊ณ , @Service๋Š” ์„œ๋น„์Šค์˜ ๋กœ์ง, @Repository ์–ด๋…ธํ…Œ์ด์…˜์€ DB์—์„œ ๋™์ž‘ํ•˜๋Š” Persistence ๋ ˆ์ด์–ด๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.

๊ธฐ๋Šฅ ์—ญํ• ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๋Š” ๋ ˆ์ด์–ด๋ผ๋ฉด Component ๋ณด๋‹ค๋Š” ๊ตฌ์ฒด์ ์ธ ์Šคํ…Œ๋ ˆ์˜ค ํƒ€์ž…์ธ ํ•˜์œ„ ์–ด๋…ธํ…Œ์ด์…˜์„ ๊ถŒ์žฅํ•œ๋‹ค.

DTO (Converter vs Mapper)

์‹ค์ œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” Entity ๋กœ ์กฐํšŒํ•œ DB์˜ ๊ฐ์ฒด๋ฅผ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด DTO์— ๋งคํ•‘๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ ์ด๋ฅผ ์น˜ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜๋งŽ์€ DTO์˜ Setter, Getter ์ค‘๋ณต์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์ธ Entity๋“ค์„ ๋ฐ”๋กœ API์˜ ๊ฒฐ๊ณผ๋กœ ๋…ธ์ถœํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐ ํ•˜๊ธฐ ์œ„ํ•ด DTO ๋ ˆ์ด์–ด๋ฅผ ๋‘์–ด์•ผ ํ•˜๋ฉฐ, ์ด DTO๋“ค์˜ Converter ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ํŒจํ„ด์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•ด์•ผ ํ•œ๋‹ค.

์–‘๋ฐฉํ–ฅ์ด ์•„๋‹Œ ๋‹จ๋ฐฉํ–ฅ ๋ณ€ํ™˜์˜ ๊ฒฝ์šฐ์—๋Š” Mapper (ํ•œ ๊ฐœ์ฒด์˜ ์†์„ฑ์„ ๋‹ค๋ฅธ ๊ฐœ์ฒด๋กœ ๋ณต์‚ฌํ•  ๊ฒฝ์šฐ) ๋ผ๊ณ  ๋ช…๋ช…ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

Converter ํŒจํ„ด์˜ ๋ชฉ์ ์€ ํ•ด๋‹น ํ˜•์‹ ๊ฐ„์— ์ผ๋ฐ˜์ ์ธ ์–‘๋ฐฉํ–ฅ ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์—ฌ ๊น”๋”ํ•œ ๊ตฌํ˜„์„ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. Converter ํŒจํ„ด์„ ํ†ตํ•ด ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์„ ๋ณ€ํ™˜ํ•จ์œผ๋กœ์จ ๊ธฐ์กด ์ฝ”๋“œ๋“ค์˜ ์“ธ๋ฐ์—†๋Š” Setter/Getter ๋ฐ˜๋ณต ์ž‘์—…์„ ํ˜์‹ ์ ์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์ œ๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

public class Converter<T, U> {

  private final Function<T, U> fromDto;
  private final Function<U, T> fromEntity;

  public Converter(final Function<T, U> fromDto, final Function<U, T> fromEntity) {
    this.fromDto = fromDto;
    this.fromEntity = fromEntity;
  }

  public final U convertFromDto(final T dto) {
    return fromDto.apply(dto);
  }

  public final T convertFromEntity(final U entity) {
    return fromEntity.apply(entity);
  }

  public final List<U> createFromDtos(final Collection<T> dtos) {
    return dtos.stream().map(this::convertFromDto).collect(Collectors.toList());
  }

  public final List<T> createFromEntities(final Collection<U> entities) {
    return entities.stream().map(this::convertFromEntity).collect(Collectors.toList());
  }
}

๋ณ€ํ™˜ ํ•˜๊ณ ์ž ํ•˜๋Š” ๋Œ€์ƒ ๊ฐ์ฒด๋Š” ์œ„์˜ ๊ธฐ๋ณธ Converter ์ œ๋„ค๋ฆญ์„ ์ƒ์†ํ•˜์—ฌ ๊ตฌํ˜„ํ•œ๋‹ค.

public class UserConverter extends Converter<UserDto, User> {

  public UserConverter() {
      super(UserConverter::convertToEntity, UserConverter::convertToDto);
  }

  private static UserDto convertToDto(User user) {
      return new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId());
  }

  private static User convertToEntity(UserDto dto) {
      return new User(dto.getFirstName(), dto.getLastName(), dto.isActive(), dto.getEmail());
  }

}

UserDto ์™€ User Entity ์˜ ๋ณ€ํ™˜์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

var userConverter = new UserConverter();
var dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
var user = userConverter.convertFromDto(dtoUser);

๊ทธ๋ฆผ 1-2

๊ทธ๋ฆผ 2

UserConvert ๋ฅผ ํ†ตํ•ด dto์™€ entity ์‚ฌ์ด์˜ ์–‘๋ฐฉํ–ฅ ๋ณ€ํ™˜์„ ์ข€ ๋” ๋ช…ํ™•ํ•˜๊ณ  ์‹ฌํ”Œํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ œ๋„ˆ๋ฆญ ์ฝ”๋“œ์˜ ํ™•์žฅ์„ฑ์— ๋Œ€ํ•ด์„œ ๊ต‰์žฅํžˆ ์œ ์—ฐํ•œ ์ฝ”๋“œ๋“ค์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฏ€๋กœ์จ Converter ์ฝ”๋“œ๋“ค๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ฑ์„ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค์ˆ˜๋„ ์žˆ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ ModelMapper (์ฐธ๊ณ  ๋งํฌ : https://modelmapper.org/getting-started/)๊ฐ€ ์œ ์šฉํ•œ๋ฐ, ์•„๋ž˜์™€ ๊ฐ™์ด ์ œ๋„ˆ๋ฆญ์œผ๋กœ ํ™•์žฅํ•ด์„œ ํด๋ž˜์Šค๊ฐ„์˜ ๋ณ€ํ™˜์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

/**
 * @author CodeVillains
 */
@Component
public class EntityConverter {
    private final ModelMapper modelMapper;
    public EntityConverter(ModelMapper modelMapper) {
        this.modelMapper = modelMapper;
    }

    public <S, D> D convertToDto(S entity, Class<D> dto) {
        return modelMapper.map(entity, dto);
    }

    public <S, D> D convertToEntity(S dto, Class<D> entity) {
        return modelMapper.map(dto, entity);
    }

}

์ด ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

private final GoalService goalService;
private final EntityConverter entityConverter;
...

public GoalResponse findById(Long id) {
    Goal goal = goalService.findById(id).orElseThrow(() -> new GoalNotFoundException(id));
    GoalResponse response = entityConverter.convertToDto(goal, GoalResponse.class);  // entity to dto 
    return response;
}

Converter ํด๋ž˜์Šค๋ณด๋‹ค ModelMapper ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ EntityConverter ๊ฐ€ ์ฝ”๋“œ์ƒ์œผ๋กœ ํ›จ์”ฌ ์ดํ•ดํ•˜๊ธฐ ํŽธํ•  ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ List ํƒ€์ž…์˜ ์˜ค๋ธŒ์ ํŠธ ๋งคํ•‘์„ ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€ํ™˜ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

public <S, D> List<D> convertListToDto(List<S> sourceList, Class<D> destinationType) {
    return sourceList.stream()
            .map(source -> modelMapper.map(source, destinationType))
            .collect(Collectors.toList());
}

public <S, D> List<D> convertListToEntity(List<S> sourceList, Class<D> destinationType) {
    return sourceList.stream()
            .map(source -> modelMapper.map(source, destinationType))
            .collect(Collectors.toList());
}

์‹ค์ œ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์˜ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

List<DtoClass> dtoList = converter.convertListToDto(entityList, DtoClass.class);
for (DtoClass dto : dtoList) {
    System.out.println(dto.getId());
    System.out.println(dto.getName());
}

List<EntityClass> convertedEntityList = converter.convertListToEntity(dtoList, EntityClass.class);
for (EntityClass entity : convertedEntityList) {
    System.out.println(entity.getId());
    System.out.println(entity.getName());
}