๐ŸŽฏ 1์ฃผ์ฐจ Unit 1.1-2 โ€” ์ ˆ์ฐจ์ง€ํ–ฅ vs ๊ฐ์ฒด์ง€ํ–ฅ

Psjยท2026๋…„ 5์›” 6์ผ

F-lab

๋ชฉ๋ก ๋ณด๊ธฐ
22/52

๐ŸŽฏ Unit 1.1-2 โ€” ์ ˆ์ฐจ์ง€ํ–ฅ vs ๊ฐ์ฒด์ง€ํ–ฅ

F-lab Java 1์ฃผ์ฐจ / Phase 1 / Unit 1.1 ๋ณธ๊ฒฉ ํ•™์Šต ์ž๋ฃŒ
9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ ํ˜•์‹์œผ๋กœ ๊นŠ์ด ํŒŒํ—ค์นœ๋‹ค.

์„ ์ˆ˜ ์ง€์‹: ์—†์Œ (ํ•™์Šต ์—ฌ์ •์˜ ์ถœ๋ฐœ์ )
๋‹ค์Œ Unit: 1.2 โ€” ํด๋ž˜์Šค์™€ ๊ฐ์ฒด์˜ ๋ณธ์งˆ


๐ŸŒ 1. ์„ธ์ƒ ์† ๋น„์œ 

์ ˆ์ฐจ์ง€ํ–ฅ์˜ ํ•œ๊ณ„์™€ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ๋“ฑ์žฅ

๊ฒฐ๋ก ๋ถ€ํ„ฐ

๊ฐ€์žฅ ๊ทผ๋ณธ์ ์ธ ์ฐจ์ด๋Š” "๋ฐ์ดํ„ฐ์˜ ์ฃผ์ธ์ด ๋ˆ„๊ตฌ๋ƒ" ์ด๋‹ค.

  • ์ ˆ์ฐจ์ง€ํ–ฅ: ๋ฐ์ดํ„ฐ๋Š” ์ฃผ์ธ์ด ์—†๋‹ค. ๋ˆ„๊ตฌ๋‚˜ ๊ฐ€์ ธ๋‹ค ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ์ฒด์ง€ํ–ฅ: ๋ฐ์ดํ„ฐ๋Š” ์ฃผ์ธ(๊ฐ์ฒด)์ด ์žˆ๋‹ค. ์ฃผ์ธ์„ ํ†ตํ•ด์„œ๋งŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

์ด ์ฐจ์ด๋Š” ์‚ฌ๊ณ ๋ฐฉ์‹์—์„œ๋„ ๋“œ๋Ÿฌ๋‚œ๋‹ค:

  • ์ ˆ์ฐจ์ง€ํ–ฅ์€ "๋™์‚ฌ" ์ค‘์‹ฌ โ€” "๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ๊ฐ€" (ํ–‰๋™์˜ ์ˆœ์„œ๊ฐ€ ์ฃผ์ธ๊ณต)
  • ๊ฐ์ฒด์ง€ํ–ฅ์€ "๋ช…์‚ฌ" ์ค‘์‹ฌ โ€” "๋ฌด์—‡์ด ์žˆ๋Š”๊ฐ€" (๊ฐ์ฒด๊ฐ€ ์ฃผ์ธ๊ณต)

๊ฐ์ฒด์ง€ํ–ฅ์€ ์ ˆ์ฐจ์ง€ํ–ฅ์˜ 3๊ฐ€์ง€ ํฐ ๋ฌธ์ œ ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.


๐ŸŽฌ ์‚ฌ๊ณ ๋ฐฉ์‹์˜ ์ฐจ์ด โ€” "๋™์‚ฌ vs ๋ช…์‚ฌ"

๊ฐ™์€ ์ผ์„ ๋‘ ๋ฐฉ์‹์œผ๋กœ ํ‘œํ˜„ํ•ด๋ณด์ž.

์ƒํ™ฉ: ๊ฐ•์•„์ง€๋ฅผ ์ง–๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค.

์ ˆ์ฐจ์ง€ํ–ฅ โ€” ๋™์‚ฌ ์ค‘์‹ฌ

์ง–๊ฒŒ_ํ•˜๋‹ค(๊ฐ•์•„์ง€)

โ†’ "์ง–๋‹ค" ๋ผ๋Š” ๋™์‚ฌ(ํ•จ์ˆ˜) ๊ฐ€ ์ฃผ์ธ๊ณต
โ†’ ๊ฐ•์•„์ง€๋Š” ๊ทธ๋ƒฅ ์žฌ๋ฃŒ(๋ฐ์ดํ„ฐ)
โ†’ ์‚ฌ๊ณ  ํ๋ฆ„: "์ง–๋Š” ํ–‰๋™์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ?"

๊ฐ์ฒด์ง€ํ–ฅ โ€” ๋ช…์‚ฌ ์ค‘์‹ฌ

๊ฐ•์•„์ง€.์ง–๋‹ค()

โ†’ "๊ฐ•์•„์ง€" ๋ผ๋Š” ๋ช…์‚ฌ(๊ฐ์ฒด) ๊ฐ€ ์ฃผ์ธ๊ณต
โ†’ ์ง–๋Š” ๋Šฅ๋ ฅ์€ ๊ฐ•์•„์ง€๊ฐ€ ์†Œ์œ 
โ†’ ์‚ฌ๊ณ  ํ๋ฆ„: "๋ˆ„๊ฐ€ ์ง–๋Š” ์ฑ…์ž„์„ ๊ฐ€์งˆ๊นŒ?"


๊ฐ™์€ ์ผ, ๋‹ค๋ฅธ ์‹œ๊ฐ

์ ˆ์ฐจ์ง€ํ–ฅ (๋™์‚ฌ ์ค‘์‹ฌ)๊ฐ์ฒด์ง€ํ–ฅ (๋ช…์‚ฌ ์ค‘์‹ฌ)
์ฝ”๋“œ ํ˜•ํƒœ์ง–๊ฒŒ_ํ•˜๋‹ค(๊ฐ•์•„์ง€)๊ฐ•์•„์ง€.์ง–๋‹ค()
์ฃผ์ธ๊ณต๋™์‚ฌ (ํ–‰๋™)๋ช…์‚ฌ (๊ฐ์ฒด)
์‚ฌ๊ณ "์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ""๋ˆ„๊ฐ€ ์ฑ…์ž„์งˆ๊นŒ"
๋ฐ์ดํ„ฐํ•จ์ˆ˜์— ์ „๋‹ฌ๋จ๊ฐ์ฒด๊ฐ€ ์†Œ์œ ํ•จ
๋ช…๋ น ๋ฐฉ์‹"์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ด""๋„ˆ ์ด๊ฑฐ ํ•ด"

์ด ์‚ฌ๊ณ ๋ฐฉ์‹์˜ ์ฐจ์ด๊ฐ€ ๋งˆ์„์˜ ์ง„ํ™” ๋น„์œ ๋กœ ํ’€์–ด๋ณด๋ฉด ๋” ๋ช…ํ™•ํ•ด์ง„๋‹ค.


๐Ÿ˜๏ธ ์ „์ฒด ๋น„์œ  โ€” "๋งˆ์„์˜ ์ง„ํ™”"

์˜›๋‚  ํ•œ ๋งˆ์„์ด ์žˆ์—ˆ๋‹ค. ์ฒ˜์Œ์—” ์ž‘์€ ๋งˆ์„์ด์—ˆ์ง€๋งŒ ์ ์  ์ปค์กŒ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๊ณ , ๋งˆ์„์˜ ์šด์˜ ๋ฐฉ์‹์ด ์ง„ํ™”ํ–ˆ๋‹ค.

์ด ๋งˆ์„์˜ ์ด์•ผ๊ธฐ๊ฐ€ ๊ณง ์ ˆ์ฐจ์ง€ํ–ฅ์—์„œ ๊ฐ์ฒด์ง€ํ–ฅ์œผ๋กœ์˜ ์ง„ํ™” ์ด์•ผ๊ธฐ๋‹ค.


1๋‹จ๊ณ„ โ€” ์ ˆ์ฐจ์ง€ํ–ฅ์˜ ์‹œ๋Œ€ (์ž‘์€ ๋งˆ์„)

๋งˆ์„์˜ ๋ชจ์Šต

๋งˆ์„ ํ•œ๊ฐ€์šด๋ฐ์— ๊ณต๋™ ์ฐฝ๊ณ  ๊ฐ€ ์žˆ๋‹ค. ๋ชจ๋“  ๋งˆ์„ ์‚ฌ๋žŒ์˜ ๋ฌผ๊ฑด์ด ์—ฌ๊ธฐ์— ๋ชจ์—ฌ์žˆ๋‹ค.

  • ์ฒ ์ˆ˜์˜ ์Œ€
  • ์˜ํฌ์˜ ์˜ท
  • ๋ฏผ์ˆ˜์˜ ๋„๊ตฌ
  • ... ๋ชจ๋‘ ํ•œ ์ฐฝ๊ณ ์—

๋งˆ์„ ์‚ฌ๋žŒ๋“ค์€ "์ผ๊พผ" ๋“ค. ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ํ• ์ง€๋Š” ์ •ํ•ด์ ธ ์žˆ๋‹ค:

  • ์ผ๊พผ A: ์š”๋ฆฌ ๋‹ด๋‹น โ†’ ์ฐฝ๊ณ ์—์„œ ์Œ€ ๊ฐ€์ ธ๊ฐ€์„œ ๋ฐฅ ํ•จ
  • ์ผ๊พผ B: ๋นจ๋ž˜ ๋‹ด๋‹น โ†’ ์ฐฝ๊ณ ์—์„œ ์˜ท ๊ฐ€์ ธ๊ฐ€์„œ ๋นจ๋ž˜
  • ์ผ๊พผ C: ์ฒญ์†Œ ๋‹ด๋‹น โ†’ ์ฐฝ๊ณ ์—์„œ ๋„๊ตฌ ๊ฐ€์ ธ๊ฐ€์„œ ์ฒญ์†Œ

๋งˆ์„์ด ์ž‘์„ ๋• ์ด ๋ฐฉ์‹์ด ์ž˜ ๊ตด๋Ÿฌ๊ฐ”๋‹ค.

[๊ณต๋™ ์ฐฝ๊ณ : ์Œ€, ์˜ท, ๋„๊ตฌ, ...]  โ† ๋ฐ์ดํ„ฐ (๋ช…์‚ฌ)
       โ†“ (๊ฐ€์ ธ๊ฐ)
[์ผ๊พผ A] โ†’ ์š”๋ฆฌ              โ† ํ•จ์ˆ˜ (๋™์‚ฌ)
[์ผ๊พผ B] โ†’ ๋นจ๋ž˜              โ† ํ•จ์ˆ˜ (๋™์‚ฌ)
[์ผ๊พผ C] โ†’ ์ฒญ์†Œ              โ† ํ•จ์ˆ˜ (๋™์‚ฌ)

โ†’ ์—ฌ๊ธฐ์„œ ์ฃผ์ธ๊ณต์€ ์ผ๊พผ(๋™์‚ฌ) ์ด๋‹ค. ์ฐฝ๊ณ ๋Š” ๊ทธ๋ƒฅ ์žฌ๋ฃŒ ๋ณด๊ด€์†Œ.
โ†’ ์ฝ”๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€: ์š”๋ฆฌํ•˜๋‹ค(์Œ€), ๋นจ๋ž˜ํ•˜๋‹ค(์˜ท) โ€” ๋™์‚ฌ๊ฐ€ ์ฃผ์ธ๊ณต.

C ์–ธ์–ด ์ฝ”๋“œ๋กœ ๋ณด๋ฉด

// ๊ณต๋™ ์ฐฝ๊ณ  = ๊ตฌ์กฐ์ฒด์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋ชจ์Œ (๋ช…์‚ฌ โ€” ๋‹จ์ˆœ ์žฌ๋ฃŒ)
struct Warehouse {
    int chulsuRice;       // ์ฒ ์ˆ˜์˜ ์Œ€
    char younghuiClothes[100];  // ์˜ํฌ์˜ ์˜ท
    char minsuTools[100];       // ๋ฏผ์ˆ˜์˜ ๋„๊ตฌ
};

// ์ผ๊พผ๋“ค = ๋…๋ฆฝ๋œ ํ•จ์ˆ˜๋“ค (๋™์‚ฌ โ€” ์ฃผ์ธ๊ณต)
void cook(struct Warehouse* w) {
    // ์ฐฝ๊ณ ์—์„œ ์Œ€ ๊ฐ€์ ธ๊ฐ€์„œ ๋ฐฅ ํ•จ
    w->chulsuRice -= 10;
    printf("๋ฐฅ ์™„์„ฑ\n");
}

void wash(struct Warehouse* w) {
    // ์ฐฝ๊ณ ์—์„œ ์˜ท ๊ฐ€์ ธ๊ฐ€์„œ ๋นจ๋ž˜
    printf("%s ๋นจ๋ž˜ ์™„๋ฃŒ\n", w->younghuiClothes);
}

void clean(struct Warehouse* w) {
    // ์ฐฝ๊ณ ์—์„œ ๋„๊ตฌ ๊ฐ€์ ธ๊ฐ€์„œ ์ฒญ์†Œ
    printf("%s๋กœ ์ฒญ์†Œ\n", w->minsuTools);
}

// ์‚ฌ์šฉ โ€” ๋™์‚ฌ(ํ•จ์ˆ˜)๊ฐ€ ์ฃผ์ธ๊ณต, ๋ช…์‚ฌ(๋ฐ์ดํ„ฐ)๋Š” ์ธ์ž๋กœ ๋„˜๊ฒจ์ง
int main() {
    struct Warehouse warehouse = { 50, "์…”์ธ ", "๋น—์ž๋ฃจ" };
    cook(&warehouse);   // "์š”๋ฆฌํ•˜๋‹ค(์ฐฝ๊ณ )" โ€” ๋™์‚ฌ ์ค‘์‹ฌ
    wash(&warehouse);   // "๋นจ๋ž˜ํ•˜๋‹ค(์ฐฝ๊ณ )" โ€” ๋™์‚ฌ ์ค‘์‹ฌ
    clean(&warehouse);  // "์ฒญ์†Œํ•˜๋‹ค(์ฐฝ๊ณ )" โ€” ๋™์‚ฌ ์ค‘์‹ฌ
}

โ†’ ์ด๊ฒŒ ์ ˆ์ฐจ์ง€ํ–ฅ: ๋ฐ์ดํ„ฐ(์ฐฝ๊ณ  ๊ตฌ์กฐ์ฒด) ์™€ ํ–‰๋™(ํ•จ์ˆ˜) ์ด ๋ถ„๋ฆฌ๋จ. ํ•จ์ˆ˜(๋™์‚ฌ)๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌ.


์ ˆ์ฐจ์ง€ํ–ฅ์˜ 3๊ฐ€์ง€ ํฐ ๋ฌธ์ œ

๋งˆ์„์ด ์ปค์ง€๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ํญ๋ฐœํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค.

๋ฌธ์ œ 1: ๋ฐ์ดํ„ฐ๊ฐ€ ์—‰๋ง์ด ๋จ (๋ฌด๊ฒฐ์„ฑ ๋ถ•๊ดด)

์ƒํ™ฉ: ๊ณต๋™ ์ฐฝ๊ณ ์— ๋ˆ„๊ตฌ๋‚˜ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ์ผ๊พผ A๊ฐ€ ์‹ค์ˆ˜๋กœ ์˜ํฌ์˜ ์˜ท์„ ๊ฐ€์ ธ๊ฐ€์„œ ํ–‰์ฃผ๋กœ ์”€
  • ์ผ๊พผ B๊ฐ€ ๋ฏผ์ˆ˜์˜ ๋„๊ตฌ๋ฅผ ๋นจ๋ž˜ํŒ์œผ๋กœ ์”€
  • ๋ˆ„๊ตฐ๊ฐ€ ์Œ€์„ ์Œ์ˆ˜๋กœ ๊ธฐ๋กํ•จ (-50kg) โ€” ๋ง‰์„ ๋ฐฉ๋ฒ• ์—†์Œ
  • ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ๋ง๊ฐ€๋œจ๋ ธ๋Š”์ง€ ์ถ”์  ๋ถˆ๊ฐ€

์™œ ๊ทธ๋Ÿด๊นŒ? ๋ฐ์ดํ„ฐ๋Š” ์ฃผ์ธ ์—†๋Š” ๋ช…์‚ฌ ๋ผ์„œ, ๋™์‚ฌ(ํ•จ์ˆ˜)๋“ค์ด ๋งˆ์Œ๋Œ€๋กœ ๋งŒ์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ.

C ์–ธ์–ด ์ฝ”๋“œ๋กœ ๋ณด๋ฉด

struct Warehouse warehouse = { 50, "์…”์ธ ", "๋น—์ž๋ฃจ" };

// ๋ˆ„๊ตฌ๋‚˜ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ์งˆ ์ˆ˜ ์žˆ์Œ โ€” ๋ช…์‚ฌ๊ฐ€ ๋ณดํ˜ธ๋ฐ›์ง€ ๋ชปํ•จ
warehouse.chulsuRice = -99999;        // ์Œ์ˆ˜? ๊ฐ€๋Šฅ โŒ
strcpy(warehouse.younghuiClothes, "");  // ๋นˆ ๋ฌธ์ž์—ด? ๊ฐ€๋Šฅ โŒ
strcpy(warehouse.minsuTools, "๐Ÿคก");    // ์ด์ƒํ•œ ๊ฐ’? ๊ฐ€๋Šฅ โŒ

// ๊ฒ€์ฆ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋„, ํ˜ธ์ถœ ์•ˆ ํ•˜๋ฉด ๊ทธ๋งŒ
void validateRice(int rice) {
    if (rice < 0) printf("์—๋Ÿฌ!\n");
}
// โ†’ ๋ˆ„๊ตฐ๊ฐ€ validateRice ํ˜ธ์ถœ ์•ˆ ํ•˜๊ณ  ์ง์ ‘ ์ˆ˜์ •ํ•˜๋ฉด ๋ โŒ

// ๋ˆ„๊ฐ€ ๋ง๊ฐ€๋œจ๋ ธ๋Š”์ง€ ์ถ”์  ๋ถˆ๊ฐ€
// 100๊ฐœ ํ•จ์ˆ˜ ์ค‘ ์–ด๋А ํ•จ์ˆ˜๊ฐ€ chulsuRice๋ฅผ ์Œ์ˆ˜๋กœ ๋งŒ๋“ค์—ˆ๋‚˜? ๋ชจ๋ฆ„

โ†’ ๋ฐ์ดํ„ฐ(๋ช…์‚ฌ)์— ์ฃผ์ธ์ด ์—†์œผ๋‹ˆ, ๋ˆ„๊ตฌ๋‚˜ ๋ง๊ฐ€๋œจ๋ฆผ.


๋ฌธ์ œ 2: ์ƒˆ ๋งˆ์„ ์‚ฌ๋žŒ ์ถ”๊ฐ€๊ฐ€ ์ง€์˜ฅ (ํ™•์žฅ์„ฑ ๋ถ•๊ดด)

์ƒํ™ฉ: ๋งˆ์„์— ์™ธ๊ตญ์ธ ๊ฐ€์กฑ์ด ์ด์‚ฌ ์™”๋‹ค. ์ด ๊ฐ€์กฑ์€ ๋‹ค๋ฅธ ์Œ์‹์„ ๋จน๊ณ , ๋‹ค๋ฅธ ์˜ท์„ ์ž…๋Š”๋‹ค.

์ด์ œ ๋ชจ๋“  ์ผ๊พผ์—๊ฒŒ ์ƒˆ ๊ทœ์น™์„ ๊ฐ€๋ฅด์ณ์•ผ ํ•œ๋‹ค:

  • ์ผ๊พผ A (์š”๋ฆฌ): "์™ธ๊ตญ์ธ์ด๋ฉด ๋นต์„ ๊ตฝ๊ณ , ํ•œ๊ตญ์ธ์ด๋ฉด ๋ฐฅ์„ ํ•ด"
  • ์ผ๊พผ B (๋นจ๋ž˜): "์™ธ๊ตญ์ธ ์˜ท์ด๋ฉด ๋‹ค๋ฅด๊ฒŒ ๋นจ๊ณ , ํ•œ๊ตญ์ธ ์˜ท์ด๋ฉด..."
  • ์ผ๊พผ C (์ฒญ์†Œ): "์™ธ๊ตญ์ธ ์ง‘์ด๋ฉด ์‹ ๋ฐœ ์‹ ๊ณ , ํ•œ๊ตญ์ธ ์ง‘์ด๋ฉด ๋ฒ—๊ณ ..."

๋˜ ๋‹ค๋ฅธ ์™ธ๊ตญ์ธ ๊ฐ€์กฑ์ด ์˜ค๋ฉด? ๋ชจ๋“  ์ผ๊พผ์„ ๋˜ ๋‹ค ๊ฐ€๋ฅด์ณ์•ผ ํ•จ.

์™œ ๊ทธ๋Ÿด๊นŒ? ๋™์‚ฌ(ํ•จ์ˆ˜)๊ฐ€ ์ฃผ์ธ๊ณต์ด๋ผ, ๊ฐ ๋™์‚ฌ ์•ˆ์— ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค ๋„ฃ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ. ์ƒˆ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋ชจ๋“  ๋™์‚ฌ์— ์ƒˆ ๋ถ„๊ธฐ ์ถ”๊ฐ€.

C ์–ธ์–ด ์ฝ”๋“œ๋กœ ๋ณด๋ฉด

struct Person {
    char name[50];
    char nationality[20];  // "ํ•œ๊ตญ", "์™ธ๊ตญ", "์ผ๋ณธ", "์ค‘๊ตญ" ...
};

// ๋ชจ๋“  ํ•จ์ˆ˜(๋™์‚ฌ)์— if ๋ถ„๊ธฐ๊ฐ€ ๋Š˜์–ด๋‚จ
void cook(struct Person* p) {
    if (strcmp(p->nationality, "ํ•œ๊ตญ") == 0) {
        printf("๋ฐฅ์„ ํ•ฉ๋‹ˆ๋‹ค\n");
    } else if (strcmp(p->nationality, "์™ธ๊ตญ") == 0) {
        printf("๋นต์„ ๊ตฝ์Šต๋‹ˆ๋‹ค\n");
    } else if (strcmp(p->nationality, "์ผ๋ณธ") == 0) {  // ์ƒˆ ๊ตญ์  ์ถ”๊ฐ€
        printf("์Šค์‹œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค\n");
    }
    // ์ƒˆ ๊ตญ์  ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์—ฌ๊ธฐ ์ˆ˜์ • โŒ
}

void wash(struct Person* p) {
    if (strcmp(p->nationality, "ํ•œ๊ตญ") == 0) {
        printf("ํ•œ๊ตญ์‹ ๋นจ๋ž˜\n");
    } else if (strcmp(p->nationality, "์™ธ๊ตญ") == 0) {
        printf("์™ธ๊ตญ์‹ ๋นจ๋ž˜\n");
    } else if (strcmp(p->nationality, "์ผ๋ณธ") == 0) {  // ๋˜ ์ถ”๊ฐ€
        printf("์ผ๋ณธ์‹ ๋นจ๋ž˜\n");
    }
    // ๋˜ ์ˆ˜์ • โŒ
}

void clean(struct Person* p) {
    if (strcmp(p->nationality, "ํ•œ๊ตญ") == 0) { ... }
    else if (strcmp(p->nationality, "์™ธ๊ตญ") == 0) { ... }
    else if (strcmp(p->nationality, "์ผ๋ณธ") == 0) { ... }  // ๋˜๋˜ ์ถ”๊ฐ€ โŒ
}

// "์ค‘๊ตญ์ธ" ๊ฐ€์กฑ ์ถ”๊ฐ€ โ†’ ์œ„ ๋ชจ๋“  ํ•จ์ˆ˜ ์ˆ˜์ • ํ•„์š”
// ํ•จ์ˆ˜๊ฐ€ 200๊ฐœ๋ผ๋ฉด? 200๊ฐœ ๋‹ค ์ˆ˜์ • โŒ
// ํ•œ ๊ตฐ๋ฐ๋ผ๋„ ๋น ๋œจ๋ฆฌ๋ฉด? ๋ฒ„๊ทธ โŒ

โ†’ ์ƒˆ ์ข…๋ฅ˜(๋ช…์‚ฌ)๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋ชจ๋“  ๋™์‚ฌ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•จ.


๋ฌธ์ œ 3: ๋ˆ„๊ฐ€ ๋ญ˜ ํ•˜๋Š”์ง€ ๋ชจ๋ฆ„ (ํ˜‘์—… ๋ถ•๊ดด)

์ƒํ™ฉ: ๋งˆ์„ ์ธ๊ตฌ๊ฐ€ 1,000๋ช…์ด ๋˜์—ˆ๋‹ค.

  • ์ผ๊พผ์ด 500๋ช…, ์ฐฝ๊ณ  ๋ฌผ๊ฑด์ด 10๋งŒ ๊ฐœ
  • ๋ˆ„๊ฐ€ ์–ด๋–ค ๋ฌผ๊ฑด์„ ๋งŒ์ง€๋Š”์ง€ ์ถ”์  ๋ถˆ๊ฐ€
  • ํ•œ ์ผ๊พผ์ด ๊ทœ์น™์„ ๋ฐ”๊พธ๋ฉด ๋‹ค๋ฅธ ์ผ๊พผ๋“ค์ด ์˜ํ–ฅ๋ฐ›์Œ
  • ์ƒˆ๋กœ ์˜จ ์ผ๊พผ์€ 500๋ช…์˜ ๊ทœ์น™์„ ๋‹ค ์™ธ์›Œ์•ผ ์ผํ•  ์ˆ˜ ์žˆ์Œ

C ์–ธ์–ด ์ฝ”๋“œ๋กœ ๋ณด๋ฉด

// ๊ฑฐ๋Œ€ํ•œ ๊ณต์šฉ ๋ฐ์ดํ„ฐ (์ฃผ์ธ ์—†๋Š” ๋ช…์‚ฌ)
struct VillageData {
    int totalPopulation;
    int totalRice;
    int totalClothes;
    char warehouseStatus[1000];
    // ... 100๊ฐœ ํ•„๋“œ
};

// 5,000๊ฐœ์˜ ํ•จ์ˆ˜(๋™์‚ฌ)๊ฐ€ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ์ง
void functionA(struct VillageData* v) { v->totalRice += 10; }
void functionB(struct VillageData* v) { v->totalRice -= 5; }
void functionC(struct VillageData* v) { v->totalRice = v->totalRice * 2; }
// ... ํ•จ์ˆ˜ 5,000๊ฐœ ...
void function4999(struct VillageData* v) { v->totalRice = 0; }  // ๋ˆ„๊ฐ€ ๋งŒ๋“  ํ•จ์ˆ˜?

// ์–ด๋А ๋‚  totalRice ๊ฐ’์ด ์ด์ƒํ•จ
// โ†’ 5,000๊ฐœ ํ•จ์ˆ˜ ์ค‘ ์–ด๋А ๊ฒŒ ์ž˜๋ชป ๊ฑด๋“œ๋ ธ๋‚˜?
// โ†’ ์ถ”์  ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅ โŒ

// ์‹ ์ž… ๊ฐœ๋ฐœ์ž๊ฐ€ ๋“ค์–ด์˜ด
// "totalRice ํ•„๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋‚˜์š”?"
// โ†’ "5,000๊ฐœ ํ•จ์ˆ˜ ๋‹ค ๋ด์•ผ ์•Œ ์ˆ˜ ์žˆ์–ด์š”" โŒ

// ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ totalRice๋ฅผ long์œผ๋กœ ๋ฐ”๊พธ๋ฉด
// โ†’ 5,000๊ฐœ ํ•จ์ˆ˜ ๋ชจ๋‘ ์ˆ˜์ • ํ•„์š” โŒ

โ†’ ์‹œ์Šคํ…œ์ด ์ปค์ง€๋ฉด ํ˜‘์—… ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ.


2๋‹จ๊ณ„ โ€” ๊ฐ์ฒด์ง€ํ–ฅ์˜ ๋“ฑ์žฅ (์ปค์ง„ ๋งˆ์„์˜ ํ•ด๋ฒ•)

๋งˆ์„ ์‚ฌ๋žŒ๋“ค์ด ๋ชจ์—ฌ์„œ ๊ฒฐ์ •ํ–ˆ๋‹ค:

"๊ณต๋™ ์ฐฝ๊ณ ๋ฅผ ์—†์• ์ž. ๊ฐ์ž ์ž๊ธฐ ๋ฌผ๊ฑด์„ ์ž๊ธฐ๊ฐ€ ๊ด€๋ฆฌํ•˜์ž."

๊ทธ๋ž˜์„œ ๊ฐ์ž์˜ ์ง‘ ์„ ์ง“๊ณ , ๊ฐ์ž์˜ ๋ฌผ๊ฑด ์€ ๊ฐ์ž์˜ ์ง‘ ์— ๋‘๊ธฐ๋กœ ํ–ˆ๋‹ค.

์ƒˆ ๋งˆ์„์˜ ๋ชจ์Šต

[์ฒ ์ˆ˜์˜ ์ง‘]                  [์˜ํฌ์˜ ์ง‘]                [๋ฏผ์ˆ˜์˜ ์ง‘]
- ๊ฐ€์ง„ ๊ฒƒ: ์Œ€, ๋„๊ตฌ          - ๊ฐ€์ง„ ๊ฒƒ: ์˜ท               - ๊ฐ€์ง„ ๊ฒƒ: ๋„๊ตฌ
- ํ•  ์ค„ ์•„๋Š” ๊ฒƒ:             - ํ•  ์ค„ ์•„๋Š” ๊ฒƒ:           - ํ•  ์ค„ ์•„๋Š” ๊ฒƒ:
  โ€ข ๋ฐฅ ์ง“๊ธฐ                   โ€ข ๋นจ๋ž˜ํ•˜๊ธฐ                  โ€ข ์ฒญ์†Œํ•˜๊ธฐ
  โ€ข ์ฒญ์†Œํ•˜๊ธฐ                   โ€ข ์˜ท ์ •๋ฆฌํ•˜๊ธฐ              โ€ข ๋„๊ตฌ ์ •๋น„

ํ•ต์‹ฌ ๋ณ€ํ™”:

  • ๊ฐ ์ง‘(๋ช…์‚ฌ)์ด ์ž๊ธฐ ๋ฌผ๊ฑด์˜ ์ฃผ์ธ
  • ๊ฐ ์ง‘(๋ช…์‚ฌ)์ด ์ž๊ธฐ ํ–‰๋™๋„ ์†Œ์œ 
  • ์™ธ๋ถ€์—์„œ ์ง์ ‘ ๋งŒ์ง€๋Š” ๊ฒƒ ๊ธˆ์ง€
  • "์ฒ ์ˆ˜์•ผ, ๋ฐฅ ์ข€ ํ•ด์ค„๋ž˜?" ๋ผ๊ณ  ๋ถ€ํƒ ๋งŒ ๊ฐ€๋Šฅ
  • ์ฒ ์ˆ˜๊ฐ€ ์ž๊ธฐ ์Œ€๋กœ ์•Œ์•„์„œ ๋ฐฅ ํ•จ

โ†’ ์ด์ œ ์ฃผ์ธ๊ณต์€ ๋ช…์‚ฌ(๊ฐ์ฒด) ๋‹ค.
โ†’ ์ฝ”๋“œ๋„ ๋ฐ”๋€๋‹ค: ์š”๋ฆฌํ•˜๋‹ค(์Œ€) โ†’ ์ฒ ์ˆ˜.๋ฐฅ์ง“๋‹ค() โ€” ๋ช…์‚ฌ๊ฐ€ ์ฃผ์ธ๊ณต, ๋™์‚ฌ๋Š” ๋ช…์‚ฌ์˜ ๋Šฅ๋ ฅ.

โ†’ ์ด๊ฒŒ ๊ฐ์ฒด์ง€ํ–ฅ: ๋ฐ์ดํ„ฐ(๋ช…์‚ฌ)์™€ ํ–‰๋™(๋™์‚ฌ)์„ ๊ฐ์ฒด๊ฐ€ ํ•จ๊ป˜ ์†Œ์œ .


๊ฐ์ฒด์ง€ํ–ฅ์ด 3๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹

ํ•ด๊ฒฐ 1: ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ โ€” "์ฃผ์ธ์„ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ"

๋น„์œ : ์˜ํฌ์˜ ์˜ท์žฅ์—๋Š” ์˜ํฌ๋งŒ ์†๋Œˆ ์ˆ˜ ์žˆ๋‹ค.

  • ๋ˆ„๊ฐ€ ์™€์„œ "์˜ท ์ข€ ๋นŒ๋ ค์ค˜" ๋ถ€ํƒ โ†’ ์˜ํฌ๊ฐ€ ๊ฒ€ํ†  ํ›„ ๊ฒฐ์ •
  • ๋”๋Ÿฌ์šด ์†์œผ๋กœ ๋งŒ์ง€๋ ค ํ•˜๋ฉด โ†’ ์˜ํฌ๊ฐ€ ๊ฑฐ๋ถ€
  • ์˜ท์ด ๋ง๊ฐ€์งˆ ์ผ๋„, ์ž˜๋ชป ์“ฐ์ผ ์ผ๋„ ์—†์Œ

Java ์ฝ”๋“œ๋กœ:

public class Fare {
    private int amount;  // private โ€” ์™ธ๋ถ€ ์ง์ ‘ ์ ‘๊ทผ X
    
    public void changeAmount(int newAmount) {
        if (newAmount < 0) {
            throw new IllegalArgumentException("์Œ์ˆ˜ ๋ถˆ๊ฐ€");  // ์ž๊ธฐ๊ฐ€ ๊ฒ€์ฆ
        }
        this.amount = newAmount;
    }
}

// ์‚ฌ์šฉ โ€” ๋ช…์‚ฌ(fare)๊ฐ€ ์ฃผ์ธ๊ณต
Fare fare = new Fare();
fare.changeAmount(50000);    // "fare๊ฐ€ ์ž๊ธฐ ๊ธˆ์•ก์„ ๋ฐ”๊พผ๋‹ค" โ€” ๋ช…์‚ฌ ์ค‘์‹ฌ
fare.changeAmount(-99999);   // ์ฆ‰์‹œ ์˜ˆ์™ธ! โœ… โ€” fare ์ž์‹ ์ด ๊ฑฐ๋ถ€
// fare.amount = -99999;     // ์ปดํŒŒ์ผ ์—๋Ÿฌ! โœ… โ€” ์• ์ดˆ์— ์ ‘๊ทผ ๋ถˆ๊ฐ€

โ†’ ๋ฐ์ดํ„ฐ(๋ช…์‚ฌ)์— ์ฃผ์ธ์ด ์ƒ๊ธฐ๋‹ˆ, ์ฃผ์ธ์ด ๋ณดํ˜ธํ•จ.


ํ•ด๊ฒฐ 2: ํ™•์žฅ์ด ์‰ฌ์›Œ์ง โ€” "์ƒˆ ์ง‘์„ ์ง“๊ธฐ๋งŒ ํ•˜๋ฉด ๋จ"

๋น„์œ : ์™ธ๊ตญ์ธ ๊ฐ€์กฑ์ด ์ด์‚ฌ ์™”๋‹ค.

  • ์ƒˆ ๊ฐ€์กฑ์€ ์ž๊ธฐ ์ง‘ ์„ ์ง“๊ณ  ์ž๊ธฐ๋งŒ์˜ ๋ฐฉ์‹ ์œผ๋กœ ์‚ฐ๋‹ค
  • ๊ธฐ์กด ๋งˆ์„ ์‚ฌ๋žŒ๋“ค์€ ์‹ ๊ฒฝ ์•ˆ ์จ๋„ ๋จ
  • "์ฒ ์ˆ˜์•ผ ๋ฐฅ ์ค˜", "John, give me bread" โ€” ๊ฐ์ž ์•Œ์•„์„œ ์ฒ˜๋ฆฌ

Java ์ฝ”๋“œ๋กœ:

public abstract class Customer {
    public abstract int calculateDiscount(int amount);
}

public class VipCustomer extends Customer {
    public int calculateDiscount(int amount) { return amount * 20 / 100; }
}

public class PartnerCustomer extends Customer {
    public int calculateDiscount(int amount) { return amount * 30 / 100; }
}

// ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ โ€” ์ƒˆ ํด๋ž˜์Šค(๋ช…์‚ฌ) 1๊ฐœ๋งŒ ๋งŒ๋“ค๋ฉด ๋ โœ…
public class StudentCustomer extends Customer {
    public int calculateDiscount(int amount) { return amount * 15 / 100; }
}

// ์‚ฌ์šฉํ•˜๋Š” ์ชฝ์€ ํ•œ ์ค„๋„ ์•ˆ ๋ฐ”๋€œ
customer.calculateDiscount(amount);  // ๋ช…์‚ฌ๊ฐ€ ์•Œ์•„์„œ ์ž๊ธฐ ๋ฐฉ์‹์œผ๋กœ
// โ†’ "customer๊ฐ€ ์ž๊ธฐ ํ• ์ธ์„ ๊ณ„์‚ฐํ•œ๋‹ค" โ€” ๋ช…์‚ฌ๊ฐ€ ์ฃผ์ธ๊ณต
// โ†’ if ๋ถ„๊ธฐ ์—†์Œ, ๊ฐ ๋ช…์‚ฌ๊ฐ€ ์ž๊ธฐ ํ–‰๋™ ์ฑ…์ž„

โ†’ ์ƒˆ ๋ช…์‚ฌ(์ข…๋ฅ˜) ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ๋Š” ์•ˆ ๊ฑด๋“œ๋ฆผ.


ํ•ด๊ฒฐ 3: ํ˜‘์—…์ด ๊ฐ€๋Šฅํ•ด์ง โ€” "๊ฐ์ž ์ž๊ธฐ ์ง‘๋งŒ ์ฑ…์ž„"

๋น„์œ : 1,000๋ช…์ด ์‚ฌ๋Š” ๋งˆ์„์ด์ง€๋งŒ ์ด์ œ ์ž‘๋™ํ•œ๋‹ค.

  • ๊ฐ์ž ์ž๊ธฐ ์ง‘์˜ ์ผ ๋งŒ ์ฑ…์ž„
  • ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ง‘ ๋‚ด๋ถ€๋Š” ์•Œ ํ•„์š” ์—†์Œ
  • ์ƒˆ๋กœ ์ด์‚ฌ ์˜จ ์‚ฌ๋žŒ๋„ ์ž๊ธฐ ์ง‘๋งŒ ์ •๋ฆฌ ํ•˜๋ฉด ์ผ ์‹œ์ž‘ ๊ฐ€๋Šฅ
  • "์˜ํฌ๋„ค ์ง‘ ์ผ์€ ์˜ํฌ์—๊ฒŒ ๋ฌผ์–ด๋ด" โ€” ๋ช…ํ™•ํ•œ ์ฑ…์ž„ ๋ถ„๋‹ด

Java ์ฝ”๋“œ๋กœ:

ํ”„๋กœ์ ํŠธ ์ธ์›: 50๋ช…
- AํŒ€: Fare ํด๋ž˜์Šค(๋ช…์‚ฌ) ๋‹ด๋‹น
- BํŒ€: Customer ํด๋ž˜์Šค(๋ช…์‚ฌ) ๋‹ด๋‹น
- CํŒ€: Notification ํด๋ž˜์Šค(๋ช…์‚ฌ) ๋‹ด๋‹น

๊ฐ ํŒ€์€ ์ž๊ธฐ ๋ช…์‚ฌ๋งŒ ์ฑ…์ž„
๋‹ค๋ฅธ ํŒ€์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์€ ์•Œ ํ•„์š” X
์ธํ„ฐํŽ˜์ด์Šค(๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜)๋งŒ ์•ฝ์†ํ•˜๋ฉด ํ˜‘์—… ๊ฐ€๋Šฅ โœ…

โ†’ ๋ช…์‚ฌ๋ณ„๋กœ ์ฑ…์ž„์ด ๋ถ„๋ฆฌ๋˜๋‹ˆ ๋Œ€๊ทœ๋ชจ ํ˜‘์—… ๊ฐ€๋Šฅ.


์ •๋ฆฌ โ€” ํ•œ๋ˆˆ์— ๋ณด๋Š” ์ง„ํ™”

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

ํ•œ ๋ฌธ์žฅ ์š”์•ฝ

์ ˆ์ฐจ์ง€ํ–ฅ์€ "๋™์‚ฌ๊ฐ€ ์ฃผ์ธ๊ณต" ์ด๋ผ ๊ณต๋™ ์ฐฝ๊ณ ์— ๋ชจ๋‘์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋– ๋‹ค๋…”๊ณ , ๋ˆ„๊ตฌ๋‚˜ ๋ง๊ฐ€๋œจ๋ฆด ์ˆ˜ ์žˆ๊ณ , ์ƒˆ ์ข…๋ฅ˜ ์ถ”๊ฐ€ ์‹œ ๋ชจ๋“  ๋™์‚ฌ๋ฅผ ์žฌ๊ต์œกํ•ด์•ผ ํ–ˆ๋‹ค.

๊ฐ์ฒด์ง€ํ–ฅ์€ "๋ช…์‚ฌ๊ฐ€ ์ฃผ์ธ๊ณต" ์œผ๋กœ ๋ฐ”๋€Œ์–ด, ๊ฐ์ž์˜ ์ง‘์— ์ž๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋‘๊ณ  ์ฃผ์ธ์„ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผํ•˜๊ฒŒ ํ•จ์œผ๋กœ์จ, ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ + ํ™•์žฅ ์šฉ์ด + ํ˜‘์—… ๊ฐ€๋Šฅ์ด๋ผ๋Š” 3๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ํ•œ ๋ฒˆ์— ํ•ด๊ฒฐํ–ˆ๋‹ค.


๐Ÿ”ฅ 2. ํƒ„์ƒ ๋ฐฐ๊ฒฝ

์ ˆ์ฐจ์ง€ํ–ฅ์˜ ์‹œ๋Œ€ (1950s ~ 1980s)

์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ดˆ๊ธฐ์—๋Š” ์ ˆ์ฐจ์ง€ํ–ฅ์ด ์ž์—ฐ์Šค๋Ÿฌ์› ๋‹ค. ์™œ๋ƒํ•˜๋ฉด:

  1. ํ•˜๋“œ์›จ์–ด๊ฐ€ ์ ˆ์ฐจ์ ์ด์—ˆ๋‹ค โ€” CPU๋Š” ๋ช…๋ น์–ด๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰
  2. ํ”„๋กœ๊ทธ๋žจ์ด ์ž‘์•˜๋‹ค โ€” ํ•œ ์‚ฌ๋žŒ์ด ๋ชจ๋‘ ์ดํ•ด ๊ฐ€๋Šฅ
  3. ์ˆ˜ํ•™์  ์‚ฌ๊ณ ์™€ ๋งž์•˜๋‹ค โ€” ํ•จ์ˆ˜ f(x) = ... ์ฒ˜๋Ÿผ

๋Œ€ํ‘œ ์–ธ์–ด:

  • ํฌํŠธ๋ž€(Fortran, 1957) โ€” ๊ณผํ•™ ๊ณ„์‚ฐ
  • ์ฝ”๋ณผ(COBOL, 1959) โ€” ๋น„์ฆˆ๋‹ˆ์Šค
  • C (1972) โ€” ์‹œ์Šคํ…œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์ด ์‹œ๋Œ€์˜ ํ”„๋กœ๊ทธ๋žจ์€ "ํ•จ์ˆ˜์˜ ๋ชจ์Œ" ์ด์—ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋Š” ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ํ•จ์ˆ˜๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹.


๊ฐ์ฒด์ง€ํ–ฅ์˜ ๋“ฑ์žฅ (1960s ~ 1990s)

๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์ปค์ง€๋ฉด์„œ:

  1. ์ˆ˜๋งŒ ์ค„, ์ˆ˜์‹ญ๋งŒ ์ค„ ์ฝ”๋“œ โ€” ํ•œ ์‚ฌ๋žŒ์ด ๋‹ค ๋ชป ๋ด„
  2. ์—ฌ๋Ÿฌ ๋ช…์ด ํ˜‘์—… โ€” ๋ˆ„๊ฐ€ ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ๊ณ ์น˜๋Š”์ง€ ์ถฉ๋Œ
  3. ์œ ์ง€๋ณด์ˆ˜ ์ง€์˜ฅ โ€” ํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋ฐ”๊พธ๋ฉด ์ˆ˜๋ฐฑ ํ•จ์ˆ˜ ์ˆ˜์ •
  4. ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€ โ€” ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์—์„œ ๋ชป ๊ฐ€์ ธ์˜ด

์ด ์œ„๊ธฐ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์‹œ๋„๋กœ ๊ฐ์ฒด์ง€ํ–ฅ์ด ํƒ„์ƒ:

  • ์‹œ๋ฎฌ๋ผ(Simula 67) โ€” 1967, ์ตœ์ดˆ OOP ์–ธ์–ด (์‹œ๋ฎฌ๋ ˆ์ด์…˜์šฉ)
  • ์Šค๋ชฐํ† ํฌ(Smalltalk-80) โ€” 1980, OOP ๊ฐœ๋… ์ •๋ฆฝ โญ
  • C++ โ€” 1985, C์— OOP ์ถ”๊ฐ€ (์‹ค์šฉ์„ฑ)
  • ์ž๋ฐ”(Java) โ€” 1995, OOP์˜ ๋Œ€์ค‘ํ™” โญ

์ž๋ฐ”๋Š” "ํ”Œ๋žซํผ ๋…๋ฆฝ์„ฑ" ๊ณผ "์ˆœ์ˆ˜ OOP" ๋ฅผ ๋ฌด๊ธฐ๋กœ ํญ๋ฐœ์ ์œผ๋กœ ์„ฑ์žฅ. 90๋…„๋Œ€ ์ธํ„ฐ๋„ท ํญ๋ฐœ๊ณผ ํ•จ๊ป˜ ํ‘œ์ค€ ์–ธ์–ด๊ฐ€ ๋จ.


ํ•ต์‹ฌ ํ†ต์ฐฐ

"์ ˆ์ฐจ์ง€ํ–ฅ์€ ํ‹€๋ ธ๋‹ค ๊ฐ€ ์•„๋‹ˆ๋‹ค. ํฐ ์‹œ์Šคํ…œ์—์„œ ํ•œ๊ณ„ ๊ฐ€ ์žˆ๋‹ค."

์†Œ๊ทœ๋ชจ ์Šคํฌ๋ฆฝํŠธ๋Š” ์—ฌ์ „ํžˆ ์ ˆ์ฐจ์ง€ํ–ฅ์ด ํšจ์œจ์ . ํ•˜์ง€๋งŒ ILIC ๊ฐ™์€ 102 ํ…Œ์ด๋ธ”, 431 API ๊ทœ๋ชจ์˜ ์‹œ์Šคํ…œ์€ ๊ฐ์ฒด์ง€ํ–ฅ ์—†์ด๋Š” ๊ด€๋ฆฌ ๋ถˆ๊ฐ€๋Šฅ.


๐Ÿ’ฃ 3. ์—†์œผ๋ฉด ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ

๊ฐ์ฒด์ง€ํ–ฅ์ด ์—†๋‹ค๋ฉด? ์ ˆ์ฐจ์ง€ํ–ฅ๋งŒ์œผ๋กœ ํฐ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ ๋กœ ๋ณด์ž.

์‹œ๋‚˜๋ฆฌ์˜ค: ILIC์˜ ์šด์ž„ ๊ฒฌ์  ์‹œ์Šคํ…œ (์ ˆ์ฐจ์ง€ํ–ฅ ๋ฒ„์ „)

// ๋ฐ์ดํ„ฐ (๊ตฌ์กฐ์ฒด)
struct Fare {
    int id;
    int customerId;
    int amount;
    char status[20];
    char currency[10];
    int createdAt;
    // ... 30๊ฐœ ํ•„๋“œ
};

struct Customer {
    int id;
    char name[100];
    char email[200];
    int level;  // 0=์ผ๋ฐ˜, 1=VIP
    // ...
};

// ํ•จ์ˆ˜๋“ค
int calculateFare(struct Fare* fare, int distance);
void applyDiscount(struct Fare* fare, struct Customer* customer);
void sendNotification(struct Fare* fare, struct Customer* customer);
void saveFare(struct Fare* fare);
void validateFare(struct Fare* fare);
void printFareReceipt(struct Fare* fare);
// ... 200๊ฐœ ํ•จ์ˆ˜

๋ฌธ์ œ 1: ๋ฐ์ดํ„ฐ์™€ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ๋†€์Œ

struct Fare fare;
fare.amount = 50000;
fare.status = "DRAFT";

// ๊ฒ€์ฆ ์•ˆ ํ–ˆ๋Š”๋ฐ ์ €์žฅ ๊ฐ€๋Šฅ โŒ
saveFare(&fare);

// ๋ˆ„๊ตฐ๊ฐ€ ์ง์ ‘ ์ˆ˜์ • ๊ฐ€๋Šฅ โŒ
fare.amount = -99999;  // ์Œ์ˆ˜! ๋ฌด๊ฒฐ์„ฑ ๊นจ์ง
saveFare(&fare);

์™œ ์œ„ํ—˜ํ•œ๊ฐ€:

  • ๋ˆ„๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ์ง€๋Š”์ง€ ์ถ”์  ๋ถˆ๊ฐ€
  • ์ž˜๋ชป๋œ ์ƒํƒœ๋กœ ์ €์žฅ๋˜์–ด๋„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์žก์•„์ฃผ์ง€ ์•Š์Œ
  • 100๋ช…์ด ํ˜‘์—…ํ•˜๋ฉด ๋ˆ„๊ตฐ๊ฐ€๋Š” ๋ฐ˜๋“œ์‹œ ์ž˜๋ชป ์‚ฌ์šฉ

๋ฌธ์ œ 2: ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์‹œ ๋ชจ๋“  ํ•จ์ˆ˜ ์ˆ˜์ •

VIP ๊ณ ๊ฐ์„ ์œ„ํ•œ ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค:

// ๋ชจ๋“  ํ•จ์ˆ˜์— if ๋ถ„๊ธฐ ์ถ”๊ฐ€ โš ๏ธ
int calculateFare(struct Fare* fare, int distance) {
    if (fare->customer->level == 1) {  // VIP
        return distance * 400;  // ํ• ์ธ
    } else {
        return distance * 500;
    }
}

void applyDiscount(struct Fare* fare, struct Customer* customer) {
    if (customer->level == 1) {  // ๋˜ if!
        // VIP ํ• ์ธ
    } else {
        // ์ผ๋ฐ˜ ํ• ์ธ
    }
}

void sendNotification(struct Fare* fare, struct Customer* customer) {
    if (customer->level == 1) {  // ๋˜ if!!
        // VIP ์ „์šฉ ์•Œ๋ฆผ
    } else {
        // ์ผ๋ฐ˜ ์•Œ๋ฆผ
    }
}
// ... 200๊ฐœ ํ•จ์ˆ˜์— if ์ถ”๊ฐ€ โŒ

์™œ ๋”์ฐํ•œ๊ฐ€:

  • ์ƒˆ ๋“ฑ๊ธ‰ (PARTNER) ์ถ”๊ฐ€ โ†’ 200๊ฐœ ํ•จ์ˆ˜ ๋‹ค ์ˆ˜์ •
  • ํ•œ ๊ตฐ๋ฐ๋ผ๋„ ๋น ๋œจ๋ฆฌ๋ฉด ๋ฒ„๊ทธ
  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์ง€์˜ฅ
  • "์‹ ์ž… ๊ฐœ๋ฐœ์ž๊ฐ€ ๋“ค์–ด์˜ค๋ฉด" ์ด ๋ชจ๋“  if๋ฅผ ๋‹ค ์•Œ์•„์•ผ ํ•จ

๋ฌธ์ œ 3: ๊ฐ™์€ ์ด๋ฆ„ ํ•จ์ˆ˜ ๋ชป ๋งŒ๋“ฆ (์ด๋ฆ„ ์ถฉ๋Œ)

void send(struct Email* email);    // ์ด๋ฉ”์ผ ๋ณด๋‚ด๊ธฐ
void send(struct SMS* sms);        // ์ปดํŒŒ์ผ ์—๋Ÿฌ! โŒ
void send(struct Slack* slack);    // C์—์„œ๋Š” ๊ฐ™์€ ์ด๋ฆ„ ํ•จ์ˆ˜ X

ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ด์ƒํ•œ ์ด๋ฆ„๋“ค:

void sendEmail(...);
void sendSMS(...);
void sendSlackMessage(...);
void sendNotificationToCustomer(...);
void sendUrgentNotificationToVIPCustomer(...);  // ์ ์  ๊ธธ์–ด์ง

๋ฌธ์ œ 4: ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€

// A ํ”„๋กœ์ ํŠธ์—์„œ ๋งŒ๋“  ์šด์ž„ ๊ณ„์‚ฐ ๋กœ์ง
int calculateFare(struct Fare* fare) { ... }

// B ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ€์ ธ๋‹ค ์“ฐ๋ ค๋ฉด?
// โ†’ struct Fare ์ •์˜๋„ ๊ฐ€์ ธ์™€์•ผ ํ•จ
// โ†’ ์˜์กดํ•˜๋Š” ํ•จ์ˆ˜ 5๊ฐœ๋„ ๊ฐ€์ ธ์™€์•ผ ํ•จ
// โ†’ ๊ทธ ํ•จ์ˆ˜๋“ค์ด ์˜์กดํ•˜๋Š” ํ•จ์ˆ˜ 10๊ฐœ๋„...
// โ†’ ๊ฒฐ๊ตญ ๊ฑฐ์˜ ๋‹ค ๊ฐ€์ ธ์™€์•ผ ํ•จ โŒ

๊ฒฐ๋ก : ์ ˆ์ฐจ์ง€ํ–ฅ์˜ ํ•œ๊ณ„

ํฐ ์‹œ์Šคํ…œ์—์„œ ์ ˆ์ฐจ์ง€ํ–ฅ์€:
1. ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ ์–ด๋ ค์›€
2. ์ˆ˜์ • ์‹œ ์˜ํ–ฅ ๋ฒ”์œ„ ํญ๋ฐœ (ํ•œ ๊ณณ ๊ณ ์น˜๋ฉด 100๊ณณ)
3. ํ™•์žฅ์„ฑ ์ œ๋กœ (์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€๊ฐ€ ๋‘๋ ค์›€)
4. ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€ (๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ ํ™œ์šฉ X)
5. ํ˜‘์—… ์ง€์˜ฅ (๋ˆ„๊ฐ€ ๋ญ˜ ๋งŒ์ง€๋Š”์ง€ ๋ชจ๋ฆ„)

โ†’ ์ด ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ๊ฐ์ฒด์ง€ํ–ฅ์ด ๋“ฑ์žฅ.


โœ… 4. ํ•ด๊ฒฐ์ฑ… โ€” ๊ฐ์ฒด์ง€ํ–ฅ 4๋Œ€ ์›์น™

๊ฐ์ฒด์ง€ํ–ฅ์€ ์œ„ ๋ฌธ์ œ๋“ค์„ 4๊ฐ€์ง€ ํ•ต์‹ฌ ์›์น™ ์œผ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค. (์ด๊ฑด ๋ชจ๋“  ๋ฉด์ ‘์˜ ๋‹จ๊ณจ์ด๋‹ค โญ)

์›์น™ 1: ์บก์Аํ™” (Encapsulation)

"๋ฐ์ดํ„ฐ์™€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ–‰๋™์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ๊ณ , ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ ‘๊ทผ์„ ๋ง‰์Œ"

์œ„ ๋ฌธ์ œ 1 ํ•ด๊ฒฐ (๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ):

// ๊ฐ์ฒด์ง€ํ–ฅ ๋ฒ„์ „
public class Fare {
    private int amount;       // private โ€” ์™ธ๋ถ€ ์ง์ ‘ ์ ‘๊ทผ X
    private String status;
    
    // ๊ฒ€์ฆ๋œ ๋ฐฉ๋ฒ•์œผ๋กœ๋งŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
    public void changeAmount(int newAmount) {
        if (newAmount < 0) {
            throw new IllegalArgumentException("์Œ์ˆ˜ ๋ถˆ๊ฐ€");
        }
        this.amount = newAmount;
    }
    
    public int getAmount() {
        return this.amount;
    }
}

// ์‚ฌ์šฉ
Fare fare = new Fare();
fare.changeAmount(50000);   // OK
fare.changeAmount(-99999);  // ์ฆ‰์‹œ ์˜ˆ์™ธ! โœ…
// fare.amount = -99999;    // ์ปดํŒŒ์ผ ์—๋Ÿฌ! โœ…

ํšจ๊ณผ:

  • ๋ฐ์ดํ„ฐ๋Š” ๋‚ด๋ถ€์— ์ˆจ๊น€ (private)
  • ๊ฒ€์ฆ๋œ ๋ฐฉ๋ฒ• (๋ฉ”์„œ๋“œ) ์œผ๋กœ๋งŒ ์ ‘๊ทผ
  • ์ž˜๋ชป๋œ ์ƒํƒœ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ

์›์น™ 2: ์ƒ์† (Inheritance)

"๊ธฐ์กด ํด๋ž˜์Šค์˜ ์†์„ฑ๊ณผ ํ–‰๋™์„ ๋ฌผ๋ ค๋ฐ›์•„ ํ™•์žฅ"

์œ„ ๋ฌธ์ œ 2 ํ•ด๊ฒฐ (ํ™•์žฅ์„ฑ):

public class Customer {
    protected String name;
    protected String email;
    
    public int calculateDiscount(int amount) {
        return 0;  // ๊ธฐ๋ณธ ํ• ์ธ ์—†์Œ
    }
}

public class VipCustomer extends Customer {
    @Override
    public int calculateDiscount(int amount) {
        return amount * 20 / 100;  // 20% ํ• ์ธ
    }
}

public class PartnerCustomer extends Customer {
    @Override
    public int calculateDiscount(int amount) {
        return amount * 30 / 100;  // 30% ํ• ์ธ
    }
}

ํšจ๊ณผ:

  • ๊ณตํ†ต ๋ถ€๋ถ„ (name, email) ์€ ๋ถ€๋ชจ์— ํ•œ ๋ฒˆ๋งŒ
  • ๊ฐ์ž ๋‹ค๋ฅธ ๋ถ€๋ถ„๋งŒ ๊ตฌํ˜„
  • ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ โ†’ ์ƒˆ ํด๋ž˜์Šค 1๊ฐœ๋งŒ ๋งŒ๋“ค๋ฉด ๋จ

์›์น™ 3: ๋‹คํ˜•์„ฑ (Polymorphism)

"๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ์ฒด์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘"

์œ„ ๋ฌธ์ œ 2 ํ•ด๊ฒฐ์˜ ํ™•์žฅ:

public class FareService {
    public int calculate(Fare fare, Customer customer) {
        int baseAmount = fare.getAmount();
        int discount = customer.calculateDiscount(baseAmount);  // โญ
        return baseAmount - discount;
    }
}

// ์‚ฌ์šฉ
Customer alice = new VipCustomer();
Customer bob = new PartnerCustomer();
Customer charlie = new Customer();

fareService.calculate(fare, alice);    // 20% ํ• ์ธ ์ ์šฉ
fareService.calculate(fare, bob);      // 30% ํ• ์ธ ์ ์šฉ
fareService.calculate(fare, charlie);  // ํ• ์ธ ์—†์Œ

ํ•ต์‹ฌ ํ†ต์ฐฐ โญ :

  • FareService ์ฝ”๋“œ์— if ๋ถ„๊ธฐ๊ฐ€ ์‚ฌ๋ผ์ง
  • ๊ฐ ๊ฐ์ฒด๊ฐ€ ์ž๊ธฐ ํ–‰๋™์„ ์•Œ์•„์„œ ์ฒ˜๋ฆฌ
  • ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ํ•ด๋„ FareService ๋Š” ์†๋Œˆ ํ•„์š” X

โ†’ ์ด๊ฒŒ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์ง„์งœ ๋งˆ๋ฒ•.


์›์น™ 4: ์ถ”์ƒํ™” (Abstraction)

"๋ณต์žกํ•œ ๋‚ด๋ถ€๋ฅผ ์ˆจ๊ธฐ๊ณ  ๋ณธ์งˆ๋งŒ ๋“œ๋Ÿฌ๋ƒ„"

์œ„ ๋ฌธ์ œ 3, 4 ํ•ด๊ฒฐ:

// ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ถ”์ƒํ™”
public interface NotificationSender {
    void send(String message, String recipient);
}

// ๋‹ค์–‘ํ•œ ๊ตฌํ˜„์ฒด
public class EmailSender implements NotificationSender {
    @Override
    public void send(String message, String recipient) {
        // ์ด๋ฉ”์ผ ๋ฐœ์†ก ๋กœ์ง
    }
}

public class SMSSender implements NotificationSender {
    @Override
    public void send(String message, String recipient) {
        // SMS ๋ฐœ์†ก ๋กœ์ง
    }
}

public class SlackSender implements NotificationSender {
    @Override
    public void send(String message, String recipient) {
        // Slack ๋ฐœ์†ก ๋กœ์ง
    }
}

// ์‚ฌ์šฉ โ€” ์ถ”์ƒํ™”์˜ ํž˜
public class NotificationService {
    private NotificationSender sender;  // ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…!
    
    public void notify(String message, String recipient) {
        sender.send(message, recipient);  // ์–ด๋–ค ๊ตฌํ˜„์ด๋“  OK
    }
}

ํšจ๊ณผ:

  • ๊ฐ™์€ ์ด๋ฆ„ (send) ์œผ๋กœ ๋‹ค์–‘ํ•œ ๋™์ž‘ ๊ฐ€๋Šฅ (์ด๋ฆ„ ์ถฉ๋Œ ํ•ด๊ฒฐ)
  • ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์•Œ๋ฉด ์–ด๋–ค ๊ตฌํ˜„์ด๋“  ์‚ฌ์šฉ ๊ฐ€๋Šฅ (์žฌ์‚ฌ์šฉ์„ฑ)
  • ์ƒˆ ์•Œ๋ฆผ ์ฑ„๋„ ์ถ”๊ฐ€ ์‹œ ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋

4๋Œ€ ์›์น™ ์š”์•ฝ โญโญโญ (๋ฉด์ ‘ ๋‹จ๊ณจ)

์›์น™์˜๋ฌธํ•œ ์ค„ ์„ค๋ช…
์บก์Аํ™”Encapsulation๋ฐ์ดํ„ฐ์™€ ํ–‰๋™์„ ๋ฌถ๊ณ  ์™ธ๋ถ€ ์ ‘๊ทผ ํ†ต์ œ
์ƒ์†Inheritance๋ถ€๋ชจ์˜ ํŠน์„ฑ์„ ์ž์‹์ด ๋ฌผ๋ ค๋ฐ›์Œ
๋‹คํ˜•์„ฑPolymorphism๊ฐ™์€ ๋ฉ”์‹œ์ง€์— ๊ฐ์ฒด๋งˆ๋‹ค ๋‹ค๋ฅธ ์‘๋‹ต
์ถ”์ƒํ™”Abstraction๋ณต์žกํ•จ์„ ์ˆจ๊ธฐ๊ณ  ๋ณธ์งˆ๋งŒ ๋…ธ์ถœ

์•”๊ธฐ ํŒ: "์บก์ƒ๋‹ค์ถ”" (์บก์Аํ™”-์ƒ์†-๋‹คํ˜•์„ฑ-์ถ”์ƒํ™”)


๐Ÿ—๏ธ 5. ๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ

์ด๋ก ์„ ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๋Š”์ง€ ๋ณด์ž.

์ ˆ์ฐจ์ง€ํ–ฅ ์ฝ”๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ

// C ์ฝ”๋“œ
struct Fare {
    int amount;
    char status[20];
};

void calculateFare(struct Fare* fare) {
    fare->amount = fare->amount * 2;
}

int main() {
    struct Fare fare;
    fare.amount = 50000;
    calculateFare(&fare);
}

๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ:

[Stack]
  fare (๊ตฌ์กฐ์ฒด) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                        โ”‚
[Code ์˜์—ญ]             โ”‚
  calculateFare ํ•จ์ˆ˜ โ”€โ”€โ”€โ”€โ”˜ (ํฌ์ธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์Œ)

ํ•ต์‹ฌ:

  • ๋ฐ์ดํ„ฐ(๊ตฌ์กฐ์ฒด) ์™€ ํ•จ์ˆ˜(์ฝ”๋“œ) ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์ƒ ๋ถ„๋ฆฌ
  • ํ•จ์ˆ˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํฌ์ธํ„ฐ ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ
  • ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๊ฐ์ฒด์ง€ํ–ฅ ์ฝ”๋“œ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ

public class Fare {
    private int amount;
    
    public void doubleAmount() {
        this.amount = this.amount * 2;
    }
}

Fare fare = new Fare();
fare.doubleAmount<();

๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ (4์ฃผ์ฐจ JVM ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ):

[Stack]
  fare (์ฐธ์กฐ) โ”€โ”€โ”€โ”€โ”€โ”€โ”
                   โ”‚
[Heap]             โ”‚
  Fare ์ธ์Šคํ„ด์Šค โ—„โ”€โ”€โ”˜
   - amount: 50000
   - (๋ฉ”์„œ๋“œ๋Š” ํฌํ•จ X)
   
[Method Area]
  Fare ํด๋ž˜์Šค ์ •๋ณด
   - doubleAmount() ๋ฉ”์„œ๋“œ ์ฝ”๋“œ โญ

ํ•ต์‹ฌ ์ฐจ์ด โญ :

  • ๊ฐ์ฒด (์ธ์Šคํ„ด์Šค) ๋Š” Heap์—, ๋ฐ์ดํ„ฐ (ํ•„๋“œ) ๋งŒ ๋ณด์œ 
  • ๋ฉ”์„œ๋“œ ์ฝ”๋“œ ๋Š” Method Area์— ํด๋ž˜์Šค๋‹น ํ•œ ๋ฒŒ
  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ JVM์ด "์–ด๋А ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ์ธ๊ฐ€" ๋ฅผ ์ถ”์  (this)

this ์˜ ์ •์ฒด

public class Fare {
    private int amount;
    
    public void doubleAmount() {
        this.amount = this.amount * 2;
        //  โ†‘
        // "์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฐ์ฒด"
    }
}

Fare fare1 = new Fare(); fare1.amount = 100;
Fare fare2 = new Fare(); fare2.amount = 200;

fare1.doubleAmount();  // this = fare1, fare1.amount = 200
fare2.doubleAmount();  // this = fare2, fare2.amount = 400

JVM ๋‚ด๋ถ€:

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ JVM์ด ์ž๋™์œผ๋กœ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์ฒซ ์ธ์ž๋กœ ์ „๋‹ฌ
  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ doubleAmount(fare1) ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
  • ์šฐ๋ฆฌ ๋ˆˆ์—๋Š” ์•ˆ ๋ณด์ด์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ๋™์ž‘

๋‹คํ˜•์„ฑ์˜ ๋‚ด๋ถ€ ๋™์ž‘ โ€” Virtual Method Table (VMT)

๋‹คํ˜•์„ฑ์€ ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ• ๊นŒ? Virtual Method Table ๋•๋ถ„.

class Customer {
    public int calculateDiscount(int amount) { return 0; }
}

class VipCustomer extends Customer {
    @Override
    public int calculateDiscount(int amount) { return amount * 20 / 100; }
}

Customer c = new VipCustomer();
c.calculateDiscount(1000);  // 200 ๋ฐ˜ํ™˜ โ€” ์–ด๋–ป๊ฒŒ?

JVM์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ๋ฆ„ โญ :

1. c.calculateDiscount(1000) ํ˜ธ์ถœ
2. JVM: "c๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด์˜ ์‹ค์ œ ํด๋ž˜์Šค๋Š”?"
        โ†’ VipCustomer ์ธ์Šคํ„ด์Šค
3. JVM: "VipCustomer์˜ VMT ํ™•์ธ"
   
   Customer์˜ VMT:                VipCustomer์˜ VMT:
   [calculateDiscount โ†’ Customer.calculateDiscount]   [calculateDiscount โ†’ VipCustomer.calculateDiscount]  โญ
                                                      [์ƒ์†๋ฐ›์€ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ โ†’ Customer.xxx]
   
4. VipCustomer์˜ VMT์—์„œ calculateDiscount ์ฐพ์Œ
5. VipCustomer.calculateDiscount(1000) ์‹คํ–‰ โ†’ 200 ๋ฐ˜ํ™˜

ํ•ต์‹ฌ:

  • ์ฐธ์กฐ ํƒ€์ž… (Customer) ๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ๊ฐ์ฒด ํƒ€์ž… (VipCustomer) ์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  • ์ด๊ฒŒ ๋™์  ๋ฐ”์ธ๋”ฉ (Dynamic Binding)
  • ์ปดํŒŒ์ผ ์‹œ์ ์ด ์•„๋‹Œ ๋Ÿฐํƒ€์ž„์— ๊ฒฐ์ •

โ†’ 4-5์ฃผ์ฐจ์— ๋” ๊นŠ์ด ๋‹ค๋ฃฐ ์ฃผ์ œ. ์ง€๊ธˆ์€ "๋‹คํ˜•์„ฑ์ด ๋งˆ๋ฒ•์ด ์•„๋‹Œ VMT ๋•๋ถ„" ๋งŒ ๊ธฐ์–ต.


๐Ÿ’ป 6. ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์‹œ

ILIC ๋„๋ฉ”์ธ์œผ๋กœ ์ ˆ์ฐจ์ง€ํ–ฅ๊ณผ ๊ฐ์ฒด์ง€ํ–ฅ์„ ์ง์ ‘ ๋น„๊ตํ•ด๋ณด์ž.

์‹œ๋‚˜๋ฆฌ์˜ค: ์šด์ž„ ๊ฒฌ์  + ๊ณ ๊ฐ ๋“ฑ๊ธ‰๋ณ„ ํ• ์ธ


Bad โ€” ์ ˆ์ฐจ์ง€ํ–ฅ ์Šคํƒ€์ผ (์ž๋ฐ”๋กœ ์ž‘์„ฑํ•˜์ง€๋งŒ ์ ˆ์ฐจ์  ์‚ฌ๊ณ )

public class FareService {
    
    // ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค (Anemic Domain Model โ€” ์•ˆํ‹ฐํŒจํ„ด โš ๏ธ)
    public static class Fare {
        public int amount;
        public String status;
        public int customerId;
    }
    
    public static class Customer {
        public int id;
        public String name;
        public String level;  // "NORMAL", "VIP", "PARTNER"
    }
    
    // ๋ชจ๋“  ๋กœ์ง์ด service์— (์ ˆ์ฐจ์ง€ํ–ฅ)
    public int calculateFinalAmount(Fare fare, Customer customer) {
        int amount = fare.amount;
        
        // โŒ if ์ง€์˜ฅ ์‹œ์ž‘
        int discount = 0;
        if (customer.level.equals("VIP")) {
            discount = amount * 20 / 100;
        } else if (customer.level.equals("PARTNER")) {
            discount = amount * 30 / 100;
        } else if (customer.level.equals("NORMAL")) {
            discount = 0;
        }
        // ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ ์—ฌ๊ธฐ ์ˆ˜์ • ํ•„์š” โŒ
        
        return amount - discount;
    }
    
    public String getNotificationTemplate(Customer customer) {
        // โŒ ๋˜ if!
        if (customer.level.equals("VIP")) {
            return "VIP ๊ณ ๊ฐ๋‹˜, ์šด์ž„์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.";
        } else if (customer.level.equals("PARTNER")) {
            return "ํŒŒํŠธ๋„ˆ๋‹˜, ์šด์ž„ ์ •๋ณด๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”.";
        } else {
            return "์šด์ž„์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.";
        }
        // ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ ์—ฌ๊ธฐ๋„ ์ˆ˜์ • โŒ
    }
    
    public boolean canApplyExtraDiscount(Customer customer) {
        // โŒ ๋˜๋˜ if!
        if (customer.level.equals("VIP") || customer.level.equals("PARTNER")) {
            return true;
        }
        return false;
    }
    
    public void changeAmount(Fare fare, int newAmount) {
        // โŒ ๊ฒ€์ฆ์„ ํ˜ธ์ถœ์ž๊ฐ€ ์•Œ์•„์„œ ํ•ด์•ผ ํ•จ
        fare.amount = newAmount;  // ์Œ์ˆ˜๋„ ๋“ค์–ด๊ฐ!
    }
}

๋ฌธ์ œ์ :
1. if ์ง€์˜ฅ: ๋“ฑ๊ธ‰๋ณ„ ๋ถ„๊ธฐ๊ฐ€ ๊ณณ๊ณณ์— ํฉ์–ด์ง
2. ํ™•์žฅ ๋ถˆ๊ฐ€: ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์ˆ˜์ •
3. ๋ฌด๊ฒฐ์„ฑ X: fare.amount = -99999 ๊ฐ€๋Šฅ
4. ์‘์ง‘๋„ โ†“: ์šด์ž„ ๊ด€๋ จ ๋กœ์ง์ด service์— ๋‹ค ๋ชจ์ž„


Good โ€” ๊ฐ์ฒด์ง€ํ–ฅ ์Šคํƒ€์ผ

// 1. Customer๋Š” ์ž๊ธฐ ํ• ์ธ์„ ์•ˆ๋‹ค (๋‹คํ˜•์„ฑ)
public abstract class Customer {
    private final String name;
    private final String email;
    
    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    // ์ถ”์ƒ ๋ฉ”์„œ๋“œ โ€” ์ž์‹์ด ๊ตฌํ˜„
    public abstract int calculateDiscountRate();
    public abstract String getNotificationGreeting();
    
    // ๊ณตํ†ต ๋กœ์ง
    public int applyDiscount(int amount) {
        return amount * calculateDiscountRate() / 100;
    }
    
    public boolean canApplyExtraDiscount() {
        return calculateDiscountRate() > 0;
    }
    
    // getter
    public String getName() { return name; }
    public String getEmail() { return email; }
}

public class NormalCustomer extends Customer {
    public NormalCustomer(String name, String email) {
        super(name, email);
    }
    
    @Override
    public int calculateDiscountRate() { return 0; }
    
    @Override
    public String getNotificationGreeting() {
        return "์•ˆ๋…•ํ•˜์„ธ์š”";
    }
}

public class VipCustomer extends Customer {
    public VipCustomer(String name, String email) {
        super(name, email);
    }
    
    @Override
    public int calculateDiscountRate() { return 20; }
    
    @Override
    public String getNotificationGreeting() {
        return "VIP ๊ณ ๊ฐ๋‹˜";
    }
}

public class PartnerCustomer extends Customer {
    public PartnerCustomer(String name, String email) {
        super(name, email);
    }
    
    @Override
    public int calculateDiscountRate() { return 30; }
    
    @Override
    public String getNotificationGreeting() {
        return "ํŒŒํŠธ๋„ˆ๋‹˜";
    }
}

// 2. Fare๋Š” ์ž๊ธฐ ๋ฐ์ดํ„ฐ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ์ฑ…์ž„์ง„๋‹ค (์บก์Аํ™”)
public class Fare {
    private int amount;
    private FareStatus status;
    private final Customer customer;
    
    public Fare(int initialAmount, Customer customer) {
        validateAmount(initialAmount);
        this.amount = initialAmount;
        this.status = FareStatus.DRAFT;
        this.customer = customer;
    }
    
    public void changeAmount(int newAmount) {
        validateAmount(newAmount);
        this.amount = newAmount;
    }
    
    private void validateAmount(int amount) {
        if (amount < 0) {
            throw new IllegalArgumentException("์šด์ž„์€ ์Œ์ˆ˜์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค");
        }
    }
    
    public int calculateFinalAmount() {
        int discount = customer.applyDiscount(amount);
        return amount - discount;
    }
    
    // getter
    public int getAmount() { return amount; }
    public Customer getCustomer() { return customer; }
}

// 3. Service๋Š” ํ๋ฆ„๋งŒ ์กฐ์œจ (์–‡์•„์ง)
public class FareService {
    public int calculateFinalAmount(Fare fare) {
        return fare.calculateFinalAmount();  // ๊ฐ์ฒด์— ์œ„์ž„ โญ
    }
    
    public String createNotification(Fare fare) {
        Customer customer = fare.getCustomer();
        return String.format("%s, ์šด์ž„์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค (%d์›)",
            customer.getNotificationGreeting(),
            fare.calculateFinalAmount());
    }
}

ํšจ๊ณผ โญ :
1. if ์ง€์˜ฅ ์‚ฌ๋ผ์ง โ€” ๋‹คํ˜•์„ฑ์ด ์ฒ˜๋ฆฌ
2. ํ™•์žฅ ์‰ฌ์›€ โ€” ์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ Customer ์ž์‹๋งŒ ๋งŒ๋“ค๋ฉด ๋
3. ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ โ€” Fare ๊ฐ€ ์ž๊ธฐ ๊ฒ€์ฆ
4. ์ฑ…์ž„ ๋ถ„๋ฆฌ โ€” ๊ฐ ํด๋ž˜์Šค๊ฐ€ ์ž๊ธฐ ์ผ๋งŒ ํ•จ


์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ ๋น„๊ต โญ

์ ˆ์ฐจ์ง€ํ–ฅ:

// 5๊ฐœ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ์ˆ˜์ • ํ•„์š”
if (level.equals("STUDENT")) { ... }  // calculateFinalAmount
if (level.equals("STUDENT")) { ... }  // getNotificationTemplate
if (level.equals("STUDENT")) { ... }  // canApplyExtraDiscount
// ... ๋ชจ๋“  ๋ถ„๊ธฐ์— ์ถ”๊ฐ€

๊ฐ์ฒด์ง€ํ–ฅ:

// ์ƒˆ ํด๋ž˜์Šค 1๊ฐœ๋งŒ ๋งŒ๋“ค๋ฉด ๋!
public class StudentCustomer extends Customer {
    public StudentCustomer(String name, String email) {
        super(name, email);
    }
    
    @Override
    public int calculateDiscountRate() { return 15; }
    
    @Override
    public String getNotificationGreeting() {
        return "ํ•™์ƒ ๊ณ ๊ฐ๋‹˜";
    }
}
// ๊ธฐ์กด ์ฝ”๋“œ๋Š” ํ•œ ์ค„๋„ ์•ˆ ๊ฑด๋“œ๋ฆผ โญ

โ†’ ์ด๊ฒŒ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์ง„์งœ ๊ฐ€์น˜. SOLID์˜ OCP(Open-Closed Principle)์™€ ์ง๊ฒฐ.


โš ๏ธ 7. ์ฃผ์˜์‚ฌํ•ญ & ํ”ํ•œ ์‹ค์ˆ˜

์‹ค์ˆ˜ 1: Anemic Domain Model (๋นˆํ˜ˆ ๋„๋ฉ”์ธ ๋ชจ๋ธ)

๋นˆํ˜ˆ ๋„๋ฉ”์ธ ๋ชจ๋ธ (Anemic Domain Model) โ€” ๊นŠ์ด ๋ณด๊ธฐ

๊ฒฐ๋ก ๋ถ€ํ„ฐ

๋นˆํ˜ˆ ๋„๋ฉ”์ธ ๋ชจ๋ธ = ๊ฐ์ฒด์ง€ํ–ฅ์˜ ํƒˆ์„ ์“ด ์ ˆ์ฐจ์ง€ํ–ฅ

  • ํด๋ž˜์Šค๋Š” ๋งŒ๋“ค์–ด ๋†“์•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ(ํ•„๋“œ)๋งŒ ์žˆ๊ณ  ํ–‰๋™(๋ฉ”์„œ๋“œ)์ด ์—†๋Š” ๊ฐ์ฒด
  • ๋ชจ๋“  ๋กœ์ง์€ Service ๊ฐ™์€ ์™ธ๋ถ€ ํด๋ž˜์Šค์— ๋ชจ์—ฌ์žˆ์Œ
  • ํ˜•ํƒœ๋งŒ ์ž๋ฐ” ํด๋ž˜์Šค์ด์ง€, ์‚ฌ๊ณ ๋ฐฉ์‹์€ 100% ์ ˆ์ฐจ์ง€ํ–ฅ

์ด๋ฆ„์˜ ์œ ๋ž˜: "๋นˆํ˜ˆ(Anemic)" = ํ”ผ(์ƒ๋ช…๋ ฅ=ํ–‰๋™)๊ฐ€ ์—†๋Š” ๊ฐ์ฒด๋ผ๋Š” ๋œป. Martin Fowler๊ฐ€ 2003๋…„ ๋ช…๋ช….


๐Ÿฉธ ์™œ "๋นˆํ˜ˆ" ์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๊ฐ€

์‚ฌ๋žŒ์˜ ๋ชธ์— ๋น„์œ ํ•˜๋ฉด:

๊ฑด๊ฐ•ํ•œ ์‚ฌ๋žŒ (Rich Domain Model):

  • ๋ผˆ์™€ ์‚ด (๋ฐ์ดํ„ฐ)
  • ํ˜ˆ์•ก = ํ–‰๋™ (์ƒ๋ช…๋ ฅ, ์Šค์Šค๋กœ ์›€์ง์ž„)
  • ์ž๊ธฐ ์ผ์„ ์ž๊ธฐ๊ฐ€ ํ•จ

๋นˆํ˜ˆ ํ™˜์ž (Anemic Domain Model):

  • ๋ผˆ์™€ ์‚ด (๋ฐ์ดํ„ฐ)
  • ํ˜ˆ์•ก ์—†์Œ (์ƒ๋ช…๋ ฅ X)
  • ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์˜ฎ๊ฒจ์ค˜์•ผ ์›€์ง์ž„

โ†’ ๊ฐ์ฒด์— ์ž๊ธฐ ์ฑ…์ž„์ด ์—†์œผ๋ฉด ๋นˆํ˜ˆ.


๐Ÿ“บ ๋น„์œ  โ€” "๋ฆฌ๋ชจ์ปจ ์—†๋Š” TV"

๋นˆํ˜ˆ ๋ชจ๋ธ = ๋ฆฌ๋ชจ์ปจ ์—†๋Š” TV (์ˆ˜๋™ ๊ตฌ์‹ TV)

์˜›๋‚  TV๋ฅผ ์ƒ์ƒํ•˜์„ธ์š”:

  • TV๋Š” ๊ทธ๋ƒฅ ํ™”๋ฉด + ์Šคํ”ผ์ปค๊ฐ€ ์žˆ๋Š” ์ƒ์ž (๋ฐ์ดํ„ฐ)
  • ์ฑ„๋„์„ ๋ฐ”๊พธ๋ ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ TV ์˜† ๋‹ค์ด์–ผ์„ ๋Œ๋ ค์•ผ ํ•จ
  • ๋ณผ๋ฅจ๋„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์กฐ์ ˆ
  • ์ƒ‰์ƒ ๊ท ํ˜•๋„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘

โ†’ TV๋Š” ์ž๊ธฐ ํ–‰๋™์ด ์—†์Œ. ์‚ฌ์šฉ์ž๊ฐ€ ๋ชจ๋“  ๊ฑธ ํ•จ.

public class TV {
    private int channel;     // ๋ฐ์ดํ„ฐ๋งŒ
    private int volume;
    private int brightness;
    
    public int getChannel() { return channel; }
    public void setChannel(int channel) { this.channel = channel; }
    // ... ๋‹ค๋ฅธ getter/setter๋“ค
}

// ๋ชจ๋“  ๋กœ์ง์€ ์™ธ๋ถ€์—์„œ
public class TVUserService {
    public void changeChannel(TV tv, int newChannel) {
        if (newChannel < 1 || newChannel > 999) return;
        tv.setChannel(newChannel);
    }
    
    public void increaseVolume(TV tv) {
        int current = tv.getVolume();
        if (current < 100) tv.setVolume(current + 1);
    }
}

โ†’ TV๋Š” ์ž๊ธฐ ์ฑ„๋„/๋ณผ๋ฅจ/๋ฐ๊ธฐ๋ฅผ ๋ชจ๋ฆ„. TVUserService๊ฐ€ ๋‹ค ์•Œ์•„์•ผ ํ•จ.


์ •์ƒ ๋ชจ๋ธ = ์Šค๋งˆํŠธ TV (ํ˜„๋Œ€ TV)

ํ˜„๋Œ€ ์Šค๋งˆํŠธ TV:

  • TV๊ฐ€ ์ž๊ธฐ ํ–‰๋™์„ ๊ฐ€์ง
  • "์ฑ„๋„ ๋ฐ”๊ฟ”์ค˜" โ†’ TV๊ฐ€ ๊ฒ€์ฆ ํ›„ ์•Œ์•„์„œ ๋ฐ”๊ฟˆ
  • "๋ณผ๋ฅจ ์˜ฌ๋ ค์ค˜" โ†’ TV๊ฐ€ ์ตœ๋Œ€์น˜ ํ™•์ธํ•˜๊ณ  ์•Œ์•„์„œ ์กฐ์ ˆ
  • "๋„ทํ”Œ๋ฆญ์Šค ํ‹€์–ด์ค˜" โ†’ TV๊ฐ€ ์•Œ์•„์„œ ์ฒ˜๋ฆฌ

โ†’ TV๊ฐ€ ์ž๊ธฐ ์ผ์„ ์ž๊ธฐ๊ฐ€ ํ•จ. ์‚ฌ์šฉ์ž๋Š” ๋ช…๋ น๋งŒ.

public class SmartTV {
    private int channel;
    private int volume;
    private int brightness;
    
    // ์ž๊ธฐ ์ฑ…์ž„์„ ๊ฐ€์ง
    public void changeChannel(int newChannel) {
        if (newChannel < 1 || newChannel > 999) {
            throw new IllegalArgumentException("์œ ํšจํ•˜์ง€ ์•Š์€ ์ฑ„๋„");
        }
        this.channel = newChannel;
    }
    
    public void increaseVolume() {
        if (this.volume >= 100) return;  // ์ž๊ธฐ๊ฐ€ ํ•œ๊ณ„ ๊ฒ€์ฆ
        this.volume += 1;
    }
}

๐Ÿšจ ๋นˆํ˜ˆ ๋ชจ๋ธ์˜ ์‹ค์ œ ์‚ฌ๋ก€ โ€” ILIC ์šด์ž„ ์‹œ์Šคํ…œ

๋นˆํ˜ˆ ๋ฒ„์ „ (์•ˆํ‹ฐํŒจํ„ด)

// โŒ ๋นˆํ˜ˆ ๋ชจ๋ธ
@Entity
public class Fare {
    @Id
    private Long id;
    private int amount;
    private String status;     // "DRAFT", "SUBMITTED", "PAID", "CANCELLED"
    private Long customerId;
    private LocalDateTime createdAt;
    private LocalDateTime paidAt;
    
    // getter/setter๋งŒ ์ž”๋œฉ
    public Long getId() { return id; }
    public int getAmount() { return amount; }
    public void setAmount(int amount) { this.amount = amount; }
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    // ... 12๊ฐœ getter, 11๊ฐœ setter
}

// ๋ชจ๋“  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด Service์— ํญ์ฆ
@Service
public class FareService {
    
    public void changeAmount(Fare fare, int newAmount) {
        if (fare.getStatus().equals("PAID")) {
            throw new IllegalStateException("๊ฒฐ์ œ๋œ ์šด์ž„์€ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€");
        }
        if (newAmount < 0) {
            throw new IllegalArgumentException("์Œ์ˆ˜ ๋ถˆ๊ฐ€");
        }
        if (newAmount > 100_000_000) {
            throw new IllegalArgumentException("์ตœ๋Œ€ ๊ธˆ์•ก ์ดˆ๊ณผ");
        }
        fare.setAmount(newAmount);
    }
    
    public void submit(Fare fare) {
        if (!fare.getStatus().equals("DRAFT")) {
            throw new IllegalStateException("DRAFT ์ƒํƒœ๋งŒ ์ œ์ถœ ๊ฐ€๋Šฅ");
        }
        if (fare.getAmount() <= 0) {
            throw new IllegalStateException("๊ธˆ์•ก์ด 0 ์ดํ•˜์ธ ์šด์ž„์€ ์ œ์ถœ ๋ถˆ๊ฐ€");
        }
        fare.setStatus("SUBMITTED");
    }
    
    public void pay(Fare fare) {
        if (!fare.getStatus().equals("SUBMITTED")) {
            throw new IllegalStateException("SUBMITTED ์ƒํƒœ๋งŒ ๊ฒฐ์ œ ๊ฐ€๋Šฅ");
        }
        fare.setStatus("PAID");
        fare.setPaidAt(LocalDateTime.now());
    }
    
    public void cancel(Fare fare) {
        if (fare.getStatus().equals("PAID")) {
            throw new IllegalStateException("๊ฒฐ์ œ๋œ ์šด์ž„์€ ์ทจ์†Œ ๋ถˆ๊ฐ€");
        }
        if (fare.getStatus().equals("CANCELLED")) {
            throw new IllegalStateException("์ด๋ฏธ ์ทจ์†Œ๋จ");
        }
        fare.setStatus("CANCELLED");
    }
    
    public boolean isModifiable(Fare fare) {
        return fare.getStatus().equals("DRAFT");
    }
    
    public boolean isCancellable(Fare fare) {
        return !fare.getStatus().equals("PAID") && 
               !fare.getStatus().equals("CANCELLED");
    }
    
    // ... ์šด์ž„ ๊ด€๋ จ ๋ชจ๋“  ๋กœ์ง์ด ์—ฌ๊ธฐ์— โŒ
}

๋ฌธ์ œ์ ์ด ํ•œ๋ˆˆ์— ๋ณด์ด์‹œ๋‚˜์š”?


๋นˆํ˜ˆ ๋ชจ๋ธ์ด ๋งŒ๋“œ๋Š” 6๊ฐ€์ง€ ๊ตฌ์ฒด์  ๋ฌธ์ œ

1. ๋ฌด๊ฒฐ์„ฑ์ด ๊นจ์ง โ€” "๋ˆ„๊ตฌ๋‚˜ setter ํ˜ธ์ถœ ๊ฐ€๋Šฅ"

Fare fare = fareRepository.findById(1L);

// ์–ด๋””์„œ๋“  ์ง์ ‘ setter ํ˜ธ์ถœ ๊ฐ€๋Šฅ โŒ
fare.setAmount(-99999);          // ์Œ์ˆ˜ ๊ฐ€๋Šฅ!
fare.setStatus("๊ดด์ƒํ•œ๊ฐ’");        // ์ž˜๋ชป๋œ ์ƒํƒœ!
fare.setStatus("PAID");           // ๊ฒฐ์ œ ์•ˆ ํ–ˆ๋Š”๋ฐ ๊ฒฐ์ œ๋จ์œผ๋กœ!

// ๊ฒ€์ฆ์€ FareService ํ˜ธ์ถœํ•  ๋•Œ๋งŒ ์ผ์–ด๋‚จ
// โ†’ setter๋ฅผ ์ง์ ‘ ๋ถ€๋ฅด๋ฉด ๊ฒ€์ฆ ์šฐํšŒ

โ†’ ๊ฐ์ฒด๊ฐ€ ์ž๊ธฐ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณดํ˜ธ ๋ชปํ•จ. ๋ˆ„๊ตฌ๋‚˜ ๋ง๊ฐ€๋œจ๋ฆผ.


2. ๊ฐ™์€ ๊ฒ€์ฆ ๋กœ์ง์ด ์—ฌ๋Ÿฌ ๊ณณ์— ์ค‘๋ณต

public class FareService {
    public void changeAmount(Fare fare, int newAmount) {
        if (newAmount < 0) throw new ...;  // ๊ฒ€์ฆ 1
        // ...
    }
}

public class FareImportService {
    public void importFare(int amount, ...) {
        if (amount < 0) throw new ...;     // ๊ฐ™์€ ๊ฒ€์ฆ ๋˜ ์ž‘์„ฑ
        Fare fare = new Fare();
        fare.setAmount(amount);
    }
}

public class FareApiController {
    public void create(@RequestBody FareDto dto) {
        if (dto.getAmount() < 0) throw new ...;  // ๋˜๋˜ ์ž‘์„ฑ
    }
}

โ†’ ๋™์ผ ๊ทœ์น™์ด ์—ฌ๋Ÿฌ ๊ณณ์— ๋ถ„์‚ฐ โ†’ ํ•œ ๊ณณ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ณณ์— ๋ฒ„๊ทธ.


3. Service๊ฐ€ ๊ฑฐ๋Œ€ํ•ด์ง (God Class)

@Service
public class FareService {
    // ์šด์ž„ ์ƒ์„ฑ ๋กœ์ง
    // ์šด์ž„ ์ˆ˜์ • ๋กœ์ง
    // ์šด์ž„ ๊ฒฐ์ œ ๋กœ์ง
    // ์šด์ž„ ์ทจ์†Œ ๋กœ์ง
    // ์šด์ž„ ๊ฒ€์ฆ ๋กœ์ง
    // ํ• ์ธ ๊ณ„์‚ฐ ๋กœ์ง
    // ์ƒํƒœ ์ „์ด ๋กœ์ง
    // ... 50๊ฐœ ๋ฉ”์„œ๋“œ, 2000์ค„ โŒ
}

โ†’ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP) ์œ„๋ฐ˜. ํ…Œ์ŠคํŠธ ์–ด๋ ค์›€. ๋ณ€๊ฒฝ ์˜ํ–ฅ ํผ.


4. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ถ”์  ๋ถˆ๊ฐ€

"์šด์ž„์„ ๊ฒฐ์ œ ์ƒํƒœ๋กœ ๋ฐ”๊พธ๋Š” ๊ทœ์น™์ด ๋ญ์˜ˆ์š”?"
  โ†“
"FareService์— ์žˆ์–ด์š”"
  โ†“
"FareService์— ๋ฉ”์„œ๋“œ๊ฐ€ 50๊ฐœ์ธ๋ฐ ์–ด๋””์—..."
  โ†“
"์Œ... pay() ๋ฉ”์„œ๋“œ ๊ฐ™์•„์š”. ๊ทผ๋ฐ PaymentService์—๋„ ์žˆ๊ณ , 
 BatchService์—๋„ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ ๋กœ์ง์ด ์žˆ์–ด์„œ ์ •ํ™•ํ•œ ๋‹ต์€ ๋ชจ๋ฅด๊ฒ ๋„ค์š”"

โ†’ ๊ทœ์น™์ด ํฉ์–ด์ ธ์„œ ์ถ”์  ๋ถˆ๊ฐ€.


5. ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ค์›€

@Test
void ์šด์ž„_๊ฒฐ์ œ_ํ…Œ์ŠคํŠธ() {
    Fare fare = new Fare();
    fare.setStatus("SUBMITTED");
    fare.setAmount(50000);
    
    // Service๋ฅผ mockํ•ด์•ผ ํ•จ
    FareService service = new FareService(mockRepo, mockEventPublisher, mockAuditLogger, ...);
    service.pay(fare);
    
    assertThat(fare.getStatus()).isEqualTo("PAID");
}

vs

@Test
void ์šด์ž„_๊ฒฐ์ œ_ํ…Œ์ŠคํŠธ() {
    Fare fare = Fare.draft(50000);
    fare.submit();
    
    fare.pay();  // ๋‹จ์ˆœ!
    
    assertThat(fare.isPaid()).isTrue();
}

โ†’ ๊ฐ์ฒด ์ž์ฒด๋กœ ํ…Œ์ŠคํŠธ ๋ถˆ๊ฐ€, Service ์˜์กด์„ฑ ์ฃผ์ž… ์ง€์˜ฅ.


6. ์‹ ๊ทœ ๊ฐœ๋ฐœ์ž ์˜จ๋ณด๋”ฉ ์ง€์˜ฅ

์‹ ์ž…: "Fare๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋‚˜์š”?"
์„ ์ž„: "์Œ, FareService๋ฅผ ๋ด์•ผ ํ•ด์š”"
์‹ ์ž…: "FareService์— 50๊ฐœ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š”๋ฐ..."
์„ ์ž„: "๊ทธ๋ฆฌ๊ณ  PaymentService, FareImportService, FareBatchService๋„ ๋ด์•ผ ํ•ด์š”"
์‹ ์ž…: "............"

vs

์‹ ์ž…: "Fare๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋‚˜์š”?"
์„ ์ž„: "Fare ํด๋ž˜์Šค ์ž์ฒด๋ฅผ ๋ณด์„ธ์š”. ๊ฐ€๋Šฅํ•œ ํ–‰๋™์ด ๋‹ค ๊ฑฐ๊ธฐ ์žˆ์–ด์š”"
์‹ ์ž…: "์•„, draft(), submit(), pay(), cancel() ... ๋ช…ํ™•ํ•˜๋„ค์š”!"

โœ… ์ •์ƒ ๋ชจ๋ธ (Rich Domain Model)

๊ฐ™์€ ILIC ์šด์ž„ ์‹œ์Šคํ…œ์„ ์ •์ƒ ๋ชจ๋ธ๋กœ:

@Entity
public class Fare {
    @Id
    private Long id;
    private int amount;
    
    @Enumerated(EnumType.STRING)
    private FareStatus status;
    
    private Long customerId;
    private LocalDateTime createdAt;
    private LocalDateTime paidAt;
    
    // ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ โ€” "์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”๊ฐ€" ๋ช…ํ™•
    public static Fare draft(Long customerId, int amount) {
        validateAmount(amount);
        Fare fare = new Fare();
        fare.customerId = customerId;
        fare.amount = amount;
        fare.status = FareStatus.DRAFT;
        fare.createdAt = LocalDateTime.now();
        return fare;
    }
    
    // ํ–‰๋™ 1: ๊ธˆ์•ก ๋ณ€๊ฒฝ (์ž๊ธฐ ๊ฒ€์ฆ)
    public void changeAmount(int newAmount) {
        if (status != FareStatus.DRAFT) {
            throw new IllegalStateException("DRAFT ์ƒํƒœ์—์„œ๋งŒ ๊ธˆ์•ก ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ");
        }
        validateAmount(newAmount);
        this.amount = newAmount;
    }
    
    // ํ–‰๋™ 2: ์ œ์ถœ
    public void submit() {
        if (status != FareStatus.DRAFT) {
            throw new IllegalStateException("DRAFT ์ƒํƒœ์—์„œ๋งŒ ์ œ์ถœ ๊ฐ€๋Šฅ");
        }
        if (amount <= 0) {
            throw new IllegalStateException("๊ธˆ์•ก์ด 0 ์ดํ•˜์ธ ์šด์ž„์€ ์ œ์ถœ ๋ถˆ๊ฐ€");
        }
        this.status = FareStatus.SUBMITTED;
    }
    
    // ํ–‰๋™ 3: ๊ฒฐ์ œ
    public void pay() {
        if (status != FareStatus.SUBMITTED) {
            throw new IllegalStateException("SUBMITTED ์ƒํƒœ์—์„œ๋งŒ ๊ฒฐ์ œ ๊ฐ€๋Šฅ");
        }
        this.status = FareStatus.PAID;
        this.paidAt = LocalDateTime.now();
    }
    
    // ํ–‰๋™ 4: ์ทจ์†Œ
    public void cancel() {
        if (status == FareStatus.PAID) {
            throw new IllegalStateException("๊ฒฐ์ œ๋œ ์šด์ž„์€ ์ทจ์†Œ ๋ถˆ๊ฐ€");
        }
        if (status == FareStatus.CANCELLED) {
            throw new IllegalStateException("์ด๋ฏธ ์ทจ์†Œ๋จ");
        }
        this.status = FareStatus.CANCELLED;
    }
    
    // ์ž๊ธฐ ์ƒํƒœ ์งˆ๋ฌธ
    public boolean isModifiable() {
        return status == FareStatus.DRAFT;
    }
    
    public boolean isCancellable() {
        return status != FareStatus.PAID && status != FareStatus.CANCELLED;
    }
    
    public boolean isPaid() {
        return status == FareStatus.PAID;
    }
    
    // private ๊ฒ€์ฆ
    private static void validateAmount(int amount) {
        if (amount < 0) throw new IllegalArgumentException("์Œ์ˆ˜ ๋ถˆ๊ฐ€");
        if (amount > 100_000_000) throw new IllegalArgumentException("์ตœ๋Œ€ ๊ธˆ์•ก ์ดˆ๊ณผ");
    }
    
    // setter๋Š” ์—†์Œ โ€” ์˜๋„์ ์œผ๋กœ
    
    // getter๋Š” ํ•„์š”ํ•œ ๊ฒƒ๋งŒ
    public Long getId() { return id; }
    public int getAmount() { return amount; }
    public FareStatus getStatus() { return status; }
}

// Service๋Š” ํ๋ฆ„๋งŒ ์กฐ์œจ โ€” ์–‡์•„์ง
@Service
@RequiredArgsConstructor
public class FareService {
    private final FareRepository fareRepository;
    private final NotificationService notificationService;
    
    public Long createFare(Long customerId, int amount) {
        Fare fare = Fare.draft(customerId, amount);  // โ† ๊ฐ์ฒด์— ์œ„์ž„
        fareRepository.save(fare);
        return fare.getId();
    }
    
    @Transactional
    public void pay(Long fareId) {
        Fare fare = fareRepository.findById(fareId).orElseThrow();
        fare.pay();  // โ† ๊ฐ์ฒด์— ์œ„์ž„
        notificationService.sendPaymentConfirmation(fare);
    }
}

ํšจ๊ณผ:

  • โœ… Fare๊ฐ€ ์ž๊ธฐ ๋ฌด๊ฒฐ์„ฑ ๋ณดํ˜ธ (์ž˜๋ชป๋œ ์ƒํƒœ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ)
  • โœ… ๊ฒ€์ฆ ๋กœ์ง์ด ํ•œ ๊ณณ์—
  • โœ… Service๊ฐ€ ์–‡์Œ (ํ๋ฆ„๋งŒ ์กฐ์œจ)
  • โœ… ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ถ”์  ์‰ฌ์›€ (Fare ํด๋ž˜์Šค๋งŒ ๋ณด๋ฉด ๋จ)
  • โœ… ํ…Œ์ŠคํŠธ ์‰ฌ์›€ (Fare ๊ฐ์ฒด๋งŒ์œผ๋กœ ๊ฐ€๋Šฅ)
  • โœ… ์‹ ์ž… ์˜จ๋ณด๋”ฉ ์‰ฌ์›€

๐Ÿค” ์™œ ๋นˆํ˜ˆ ๋ชจ๋ธ์ด ๊ทธ๋ ‡๊ฒŒ ํ”ํ•œ๊ฐ€?

์ด๊ฒŒ ์•ˆํ‹ฐํŒจํ„ด์ธ ๊ฑธ ์•Œ๋ฉด์„œ๋„ ์™œ ๋งŽ์€ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋นˆํ˜ˆ ๋ชจ๋ธ์ผ๊นŒ์š”?

์ด์œ  1: JPA + Spring ํŒจํ„ด์˜ ์˜ํ–ฅ

์ „ํ˜•์ ์ธ Spring Boot ํŠœํ† ๋ฆฌ์–ผ:

[Controller] โ†’ [Service] โ†’ [Repository] โ†’ [Entity]
                  โ†‘
              ๋ชจ๋“  ๋กœ์ง์€ ์—ฌ๊ธฐ์—

์ด ๊ตฌ์กฐ๊ฐ€ "Entity๋Š” ๋ฐ์ดํ„ฐ, Service๋Š” ๋กœ์ง" ์ด๋ผ๋Š” ์ž˜๋ชป๋œ ์ธ์‹์„ ์‹ฌ์Œ.

์ด์œ  2: Lombok์˜ ํ•จ์ •

@Entity
@Getter
@Setter   // โ† ์ด๊ฑฐ ํ•œ ์ค„์ด ๋นˆํ˜ˆ ๋ชจ๋ธ ์œ ๋„
@NoArgsConstructor
@AllArgsConstructor
public class Fare {
    private int amount;
    private String status;
    // ...
}

Lombok์˜ @Setter ๊ฐ€ ์žˆ์œผ๋ฉด "setter๋กœ ๋ชจ๋“  ํ•„๋“œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ" ์ด ๊ธฐ๋ณธ ๊ฐ€์ •์ด ๋จ.

โ†’ @Setter ๋ฅผ ๋ฌด์กฐ๊ฑด ๋ถ™์ด๋Š” ์Šต๊ด€์ด ๋นˆํ˜ˆ ๋ชจ๋ธ์„ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ํฐ ์›์ธ โš ๏ธ

์ด์œ  3: ํŠธ๋žœ์žญ์…˜ ์Šคํฌ๋ฆฝํŠธ ํŒจํ„ด์ด ๋น ๋ฅธ ๊ฐœ๋ฐœ์—๋Š” ์œ ๋ฆฌ

์ž‘์€ ํ”„๋กœ์ ํŠธ, MVP ๋‹จ๊ณ„์—์„œ๋Š”:

  • ๋นˆํ˜ˆ + Service ํŒจํ„ด์ด ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Œ
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋‹จ์ˆœํ•˜๋ฉด ํฐ ๋ฌธ์ œ X

๋ฌธ์ œ๋Š” ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉด์„œ ๋น„์šฉ์ด ํญ๋ฐœํ•œ๋‹ค๋Š” ๊ฒƒ.

์ด์œ  4: ์ง„์งœ ๊ฐ์ฒด์ง€ํ–ฅ ํ•™์Šต ๋ถ€์กฑ

๋Œ€ํ•™/ํ•™์›์—์„œ ์ž๋ฐ”๋ฅผ ๋ฐฐ์šธ ๋•Œ:

  • ๋ฌธ๋ฒ• ์œ„์ฃผ
  • "Customer ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ" ์ •๋„๋งŒ
  • ๋„๋ฉ”์ธ ๋ชจ๋ธ๋ง, DDD๋Š” ๊ฑฐ์˜ ์•ˆ ๊ฐ€๋ฅด์นจ

โ†’ "๊ฐ์ฒด์ง€ํ–ฅ" ์ด๋ผ๋Š” ์ด๋ฆ„๋งŒ ์•Œ๊ณ , ๋ณธ์งˆ์€ ๋ชจ๋ฆ„.


๐Ÿšฆ ๋นˆํ˜ˆ ๋ชจ๋ธ ์ž๊ฐ€ ์ง„๋‹จ

๋ณธ์ธ ILIC ์ฝ”๋“œ๋ฅผ ์ ๊ฒ€ํ•ด๋ณด์„ธ์š”:

๋นˆํ˜ˆ ๋ชจ๋ธ ์‹ ํ˜ธ โš ๏ธ

  • Entity ํด๋ž˜์Šค์— getter/setter๋งŒ ์žˆ๋‹ค
  • @Setter ๋ฅผ ๋ชจ๋“  Entity์— ๋ถ™์ธ๋‹ค
  • Service ํด๋ž˜์Šค๊ฐ€ 1000์ค„ ์ด์ƒ์ด๋‹ค
  • ๊ฐ™์€ ๊ฒ€์ฆ ๋กœ์ง์ด ์—ฌ๋Ÿฌ Service์— ์ค‘๋ณต๋œ๋‹ค
  • Entity์˜ ์ƒํƒœ๋ฅผ ์™ธ๋ถ€์—์„œ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค
  • "์ด ๋กœ์ง์ด ์–ด๋”” ์žˆ๋‚˜" ๋ผ๋Š” ์งˆ๋ฌธ์— ์ฆ‰๋‹ตํ•˜๊ธฐ ์–ด๋ ต๋‹ค
  • Entity ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค

3๊ฐœ ์ด์ƒ ํ•ด๋‹น = ๋นˆํ˜ˆ ๋ชจ๋ธ ๊ฐ€๋Šฅ์„ฑ ๋†’์Œ.

์ •์ƒ ๋ชจ๋ธ ์‹ ํ˜ธ โœ…

  • Entity์— ์˜๋ฏธ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค (pay(), cancel() ๋“ฑ)
  • @Setter ๋Œ€์‹  ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ ๋‹ค
  • Service๋Š” ํ๋ฆ„ ์กฐ์œจ๋งŒ ํ•˜๊ณ  ์–‡๋‹ค
  • ๊ฒ€์ฆ ๋กœ์ง์ด Entity ์•ˆ์— ์žˆ๋‹ค
  • Entity๋Š” ์ž˜๋ชป๋œ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค
  • Entity ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ํ’๋ถ€ํ•˜๋‹ค

โš–๏ธ ๊ทธ๋Ÿฌ๋‚˜ โ€” ๋นˆํ˜ˆ ๋ชจ๋ธ์ด ๋ฌด์กฐ๊ฑด ๋‚˜์œ ๊ฑด ์•„๋‹ˆ๋‹ค

๊ท ํ˜• ์žกํžŒ ์‹œ๊ฐ๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋นˆํ˜ˆ ๋ชจ๋ธ์ด ์ ํ•ฉํ•œ ๊ฒฝ์šฐ

  1. CRUD๊ฐ€ ์ „๋ถ€์ธ ๋‹จ์ˆœ ์‹œ์Šคํ…œ

    • ๊ฒŒ์‹œํŒ, ๋‹จ์ˆœ ๊ด€๋ฆฌ ํŽ˜์ด์ง€
    • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฑฐ์˜ ์—†์Œ
    • โ†’ Rich Model์ด ์˜คํžˆ๋ ค ๊ณผํ•œ ์„ค๊ณ„
  2. DTO, VO

    • ๋ฐ์ดํ„ฐ ์ „๋‹ฌ๋งŒ ๋ชฉ์ 
    • ํ–‰๋™ ์—†๋Š” ๊ฒŒ ์ •์ƒ
  3. JPA Projection ๊ฒฐ๊ณผ

    • ์ฝ๊ธฐ ์ „์šฉ
    • ๋ณ€๊ฒฝ ์•ˆ ํ•จ

Rich Model์ด ํ•„์ˆ˜์ธ ๊ฒฝ์šฐ

  1. ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์ด ์žˆ๋Š” ๋„๋ฉ”์ธ

    • ILIC ์šด์ž„ ์‹œ์Šคํ…œ โญ
    • ์ƒํƒœ ์ „์ด๊ฐ€ ๋ณต์žก (DRAFT โ†’ SUBMITTED โ†’ PAID ๋“ฑ)
    • ๋‹ค์–‘ํ•œ ๊ฒ€์ฆ ๊ทœ์น™
  2. ๋ˆ, ๊ฒฐ์ œ, ๊ณ„์•ฝ ๋“ฑ ๋ฌด๊ฒฐ์„ฑ์ด ์ค‘์š”ํ•œ ๋„๋ฉ”์ธ

    • ์ž˜๋ชป๋œ ์ƒํƒœ = ์‚ฌ๊ณ 
  3. ์žฅ๊ธฐ ์œ ์ง€๋ณด์ˆ˜ ํ”„๋กœ์ ํŠธ

    • ๊ทœ์น™์ด ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ณ€ํ•จ

โ†’ ILIC๋Š” ๋ช…๋ฐฑํžˆ Rich Model์ด ํ•„์š”ํ•œ ๋„๋ฉ”์ธ.


ํ•œ ๋ฌธ์žฅ ์š”์•ฝ

๋นˆํ˜ˆ ๋„๋ฉ”์ธ ๋ชจ๋ธ์€ "๊ฐ์ฒด"๋ผ๋Š” ์ด๋ฆ„๋งŒ ๋นŒ๋ ธ์„ ๋ฟ ์‚ฌ๊ณ ๋ฐฉ์‹์€ ์ ˆ์ฐจ์ง€ํ–ฅ์ด๋‹ค.

๋ฐ์ดํ„ฐ(ํ•„๋“œ)์™€ ํ–‰๋™(๋ฉ”์„œ๋“œ)์ด ํ•จ๊ป˜ ์žˆ์–ด์•ผ ์ง„์งœ ๊ฐ์ฒด์ด๊ณ , Setter ๋‚จ๋ฐœ๊ณผ Service ๋น„๋Œ€ํ™”๋Š” ๋นˆํ˜ˆ์˜ ๊ฐ€์žฅ ํ”ํ•œ ์ฆ์ƒ์ด๋‹ค. ILIC์ฒ˜๋Ÿผ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์ด ๋ณต์žกํ•œ ๋„๋ฉ”์ธ์€ ๋ฐ˜๋“œ์‹œ Rich Domain Model๋กœ ๊ฐ€์•ผ ์žฅ๊ธฐ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.


๐ŸŽ“ ์ถ”๊ฐ€ ํ•™์Šต ์ž๋ฃŒ

๋ฐ•์Šน์ œ๋‹˜์ด ์ด ์ฃผ์ œ๋ฅผ ๋” ๊นŠ์ด ํŒŒ๊ณ  ์‹ถ๋‹ค๋ฉด:

  1. Martin Fowler, "Anemic Domain Model" (๋ธ”๋กœ๊ทธ โ€” ์›์กฐ ๊ธ€)
  2. Eric Evans, "Domain-Driven Design" (์ฑ…)
  3. "Implementing Domain-Driven Design" (Vaughn Vernon) โ€” ๋” ์‹ค์šฉ์ 
  4. 17์ฃผ์ฐจ Phase 8 โ€” Bounded Context (๋„๋ฉ”์ธ ๋ถ„๋ฆฌ)

์‹ค์ˆ˜ 2: ๋ฌด๋ถ„๋ณ„ํ•œ ์ƒ์† ๋‚จ์šฉ

๋ฌด๋ถ„๋ณ„ํ•œ ์ƒ์† ๋‚จ์šฉ โ€” ๊นŠ์ด ๋ณด๊ธฐ

๊ฒฐ๋ก ๋ถ€ํ„ฐ

์ƒ์†์€ "์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋„๊ตฌ" ๊ฐ€ ์•„๋‹ˆ๋ผ "๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋„๊ตฌ" ์ด๋‹ค.

  • "์ด ์ฝ”๋“œ ์“ฐ๊ณ  ์‹ถ์œผ๋‹ˆ๊นŒ ์ƒ์†" โ†’ โŒ ์ ˆ๋Œ€ X
  • "์ด๊ฑด ๋ช…ํ™•ํžˆ ๋ถ€๋ชจ์˜ ํ•œ ์ข…๋ฅ˜๋‹ค" โ†’ โœ… ๊ทธ๋•Œ๋งŒ ์ƒ์†

์ƒ์†์„ ์ž˜๋ชป ์“ฐ๋ฉด ์œ ์ง€๋ณด์ˆ˜ ์ง€์˜ฅ ์ด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ˜„๋Œ€ ์ž๋ฐ”์˜ ๊ฒฉ์–ธ์€:

"์ƒ์†๋ณด๋‹ค ํ•ฉ์„ฑ์„ ์„ ํ˜ธํ•˜๋ผ" (Favor Composition over Inheritance)
โ€” Joshua Bloch, Effective Java


๐Ÿค” ์™œ ์ƒ์†์ด ์œ„ํ—˜ํ•œ๊ฐ€ โ€” ๋ณธ์งˆ๋ถ€ํ„ฐ

์ƒ์†์˜ ์ง„์งœ ์˜๋ฏธ

์ƒ์†(extends)์€ ๋‹จ์ˆœํžˆ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒŒ ์•„๋‹™๋‹ˆ๋‹ค. ์„ ์–ธ์ž…๋‹ˆ๋‹ค:

public class Stack extends ArrayList { ... }

โ†’ ์ด ํ•œ ์ค„์ด ์ž๋ฐ”์—๊ฒŒ "Stack์€ ArrayList์˜ ํ•œ ์ข…๋ฅ˜๋‹ค" ๋ผ๊ณ  ์„ ์–ธํ•˜๋Š” ๊ฒƒ.

์ž๋ฐ”์™€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๊ฐ€ ์ด ์„ ์–ธ์„ ๋ฏฟ๊ณ  ํ–‰๋™ํ•จ:

  • "Stack๋„ ArrayList์ฒ˜๋Ÿผ ์“ธ ์ˆ˜ ์žˆ๊ฒ ์ง€"
  • "Stack์— ArrayList์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด๋„ ๋˜๊ฒ ์ง€"
  • "ArrayList๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ผ์„ Stack๋„ ํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€"

โ†’ ์ด๊ฒŒ ๊นจ์ง€๋ฉด ์‹œ์Šคํ…œ ์ „์ฒด๊ฐ€ ํ”๋“ค๋ฆผ.


๐ŸŽ“ ๋น„์œ  โ€” "์‚ฌ๋žŒ๊ณผ ์ง์—…"

์ด ๋น„์œ ๋กœ ์ƒ์†๊ณผ ํ•ฉ์„ฑ์˜ ์ฐจ์ด๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ž˜๋ชป๋œ ์ƒ์†

public class Doctor extends Human { ... }

โ†’ "์˜์‚ฌ๋Š” ์‚ฌ๋žŒ์˜ ํ•œ ์ข…๋ฅ˜๋‹ค" ๋ผ๋Š” ์„ ์–ธ

์ด๊ฑด ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ์˜์‚ฌ๋Š” ์‚ฌ๋žŒ์˜ ์ผ์ข…์ด๋‹ˆ๊นŒ. is-a ๊ด€๊ณ„ ๊ฐ€ ์„ฑ๋ฆฝ.


์œ„ํ—˜ํ•œ ์ƒ์†

public class Doctor extends Job { ... }

โ†’ "์˜์‚ฌ๋Š” ์ง์—…์˜ ํ•œ ์ข…๋ฅ˜๋‹ค" ๋ผ๋Š” ์„ ์–ธ

์Œ... ์ผ๋‹จ ๋ง์€ ๋ฉ๋‹ˆ๋‹ค. ์˜์‚ฌ๋„ ์ง์—…์˜ ์ผ์ข…์ด๊ธด ํ•˜๋‹ˆ๊นŒ.

๊ทธ๋Ÿฐ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์š”:

  • ์‚ฌ๋žŒ์ด ์ง์—…์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‚˜์š”? YES
  • ์‚ฌ๋žŒ์ด ๋‘ ์ง์—…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‚˜์š”? YES (์˜์‚ฌ + ์ž‘๊ฐ€)
  • ์‚ฌ๋žŒ์ด ์ง์—…์ด ์—†์„ ์ˆ˜๋„ ์žˆ๋‚˜์š”? YES

์ƒ์†์€ ๊ณ ์ •๋œ ๊ด€๊ณ„ ์ž…๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ Doctor extends Job ์œผ๋กœ ๋งŒ๋“ค๋ฉด:

  • ์˜์‚ฌ๊ฐ€ ๋‹ค๋ฅธ ์ง์—…์œผ๋กœ ๋ชป ๋ฐ”๋€œ
  • ๋‘ ์ง์—… ๊ฐ€์งˆ ์ˆ˜ ์—†์Œ (์ž๋ฐ”๋Š” ๋‹จ์ผ ์ƒ์†๋งŒ)
  • ์ง์—…์ด ์—†๋Š” ์˜์‚ฌ ํ‘œํ˜„ ๋ถˆ๊ฐ€

โ†’ "is-a" ์ฒ˜๋Ÿผ ๋ณด์—ฌ๋„ ์‚ฌ์‹ค "has-a" ์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ.


ํ•ฉ์„ฑ์œผ๋กœ ํ’€๋ฉด

public class Person {
    private Job currentJob;          // "์ง์—…์„ ๊ฐ€์ง" (has-a)
    private List<Job> sideJobs;      // "์—ฌ๋Ÿฌ ์ง์—… ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ"
    
    public void changeJob(Job newJob) {  // ์ง์—… ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ
        this.currentJob = newJob;
    }
    
    public void retire() {            // ์ง์—… ์—†์„ ์ˆ˜๋„ ์žˆ์Œ
        this.currentJob = null;
    }
}

โ†’ ์œ ์—ฐํ•จ. ์‚ฌ๋žŒ์ด ์ง์—…์„ ๊ฐ€์ง€๊ณ , ๋ฐ”๊พธ๊ณ , ์žƒ๊ณ , ์ถ”๊ฐ€ํ•˜๊ณ  โ€” ์ž์œ .


๐Ÿ’ฅ ArrayList ์ƒ์†์ด ๋งŒ๋“œ๋Š” ๊ตฌ์ฒด์  ์žฌ์•™

Stack extends ArrayList ๊ฐ€ ์™œ ๋”์ฐํ•œ์ง€ ์‹ค์ œ ์ฝ”๋“œ ์‹œ๋‚˜๋ฆฌ์˜ค ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜๋„

๋‚ด๊ฐ€ Stack์„ ๋งŒ๋“  ์ด์œ :

  • LIFO (Last In, First Out) ์ž๋ฃŒ๊ตฌ์กฐ
  • push() ์™€ pop() ๋งŒ ๋…ธ์ถœํ•˜๊ณ  ์‹ถ์Œ
  • ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ

์‹ค์ œ ๊ฒฐ๊ณผ โ€” ArrayList์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ๋…ธ์ถœ๋จ โš ๏ธ

public class Stack<E> extends ArrayList<E> {
    public void push(E item) {
        add(item);
    }
    
    public E pop() {
        return remove(size() - 1);
    }
}

์ด์ œ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ์–ด์š”:

Stack<String> stack = new Stack<>();
stack.push("A");
stack.push("B");
stack.push("C");

// LIFO๋Œ€๋กœ ์‚ฌ์šฉ โ€” OK
String top = stack.pop();  // "C"

// ๊ทธ๋Ÿฐ๋ฐ... ArrayList์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹ค ๋…ธ์ถœ๋ผ ์žˆ์Œ โŒ
stack.add(0, "X");        // ๋งจ ์•ž์— ์ถ”๊ฐ€? Stack์ด ์•„๋‹Œ๋ฐ!
stack.remove(1);          // ์ค‘๊ฐ„ ์ œ๊ฑฐ? Stack์ด ์•„๋‹Œ๋ฐ!
stack.set(0, "Y");        // ์ž„์˜ ์œ„์น˜ ์ˆ˜์ •? Stack์ด ์•„๋‹Œ๋ฐ!
stack.subList(0, 2);      // ๋ถ€๋ถ„ ๋ฆฌ์ŠคํŠธ? Stack์ด ์•„๋‹Œ๋ฐ!
stack.sort(...);          // ์ •๋ ฌ? Stack์ด ์•„๋‹Œ๋ฐ!

๋ฌธ์ œ 1: Stack์˜ ์˜๋„๊ฐ€ ๋ฌด๋„ˆ์ง. "LIFO๋งŒ ํ—ˆ์šฉ" ์ด๋ผ๋Š” ์•ฝ์†์ด ๊นจ์ง.

๋ฌธ์ œ 2: ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป ์“ฐ๋ฉด ๋””๋ฒ„๊น… ์ง€์˜ฅ.

stack.add(0, "X");  // ์‹ค์ˆ˜๋กœ 0๋ฒˆ์— ์ถ”๊ฐ€
String top = stack.pop();  // "C" (X๊ฐ€ ์•„๋‹Œ๋ฐ?)
// โ†’ ์‚ฌ์šฉ์ž: "์–ด? ๋‚ด๊ฐ€ ๋งˆ์ง€๋ง‰์— ์ถ”๊ฐ€ํ•œ ๊ฑด X์ธ๋ฐ ์™œ C๊ฐ€ ๋‚˜์˜ค์ง€?"
// โ†’ ํ•œ์ฐธ ๋””๋ฒ„๊น…ํ•˜๋‹ค add(0, ...) ๋ฐœ๊ฒฌ

๋ฌธ์ œ 3: API ์‚ฌ์šฉ์ž์—๊ฒŒ "Stack์€ ์‚ฌ์‹ค ArrayList์ž…๋‹ˆ๋‹ค" ๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์คŒ.

  • IDE ์ž๋™์™„์„ฑ์— ArrayList์˜ 50๊ฐœ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ ๋œธ
  • ์‚ฌ์šฉ์ž๋Š” ์–ด๋А ๊ฒŒ ์ง„์งœ Stack ๋ฉ”์„œ๋“œ์ธ์ง€ ํ—ท๊ฐˆ๋ฆผ

โœ… ํ•ฉ์„ฑ์œผ๋กœ ๋‹ค์‹œ ๋งŒ๋“ค๋ฉด

public class Stack<E> {
    private final List<E> items = new ArrayList<>();  // ๊ฐ€์ง (has-a)
    
    public void push(E item) {
        items.add(item);
    }
    
    public E pop() {
        if (items.isEmpty()) {
            throw new IllegalStateException("Stack is empty");
        }
        return items.remove(items.size() - 1);
    }
    
    public E peek() {
        if (items.isEmpty()) {
            throw new IllegalStateException("Stack is empty");
        }
        return items.get(items.size() - 1);
    }
    
    public int size() {
        return items.size();
    }
    
    public boolean isEmpty() {
        return items.isEmpty();
    }
}

์ด์ œ ์‚ฌ์šฉ์ž๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑด:

Stack<String> stack = new Stack<>();
stack.push("A");
stack.push("B");
stack.push("C");

stack.pop();          // OK
stack.peek();         // OK
stack.size();         // OK
stack.isEmpty();      // OK

// ์ด๊ฑด ์•ˆ ๋จ โœ…
stack.add(0, "X");    // ์ปดํŒŒ์ผ ์—๋Ÿฌ! Stack์— add ์—†์Œ
stack.remove(1);      // ์ปดํŒŒ์ผ ์—๋Ÿฌ!
stack.sort(...);      // ์ปดํŒŒ์ผ ์—๋Ÿฌ!

โ†’ Stack์˜ ์•ฝ์†์ด ์ง€์ผœ์ง. ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป ์“ธ ์ˆ˜ ์—†์Œ.


๐Ÿ”ฅ ๋” ๋ฌด์„œ์šด ์˜ˆ โ€” ์ž๋ฐ” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‹ค์ˆ˜

ํฅ๋ฏธ๋กœ์šด ์‚ฌ์‹ค: ์ž๋ฐ” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ java.util.Stack ๋„ ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

// JDK์˜ Stack โ€” ์•ˆํ‹ฐํŒจํ„ด ์‚ฌ๋ก€ โš ๏ธ
public class Stack<E> extends Vector<E> {
    public E push(E item) { addElement(item); return item; }
    public E pop() { ... }
    // ...
}

โ†’ Vector๋ฅผ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์— Vector์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ ๋…ธ์ถœ๋จ.

์ž๋ฐ” ๊ณต์‹ ๋ฌธ์„œ์—์„œ๋„ ์ธ์ •:

"A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class."

(Deque ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋” ์™„์ „ํ•˜๊ณ  ์ผ๊ด€๋œ LIFO ์Šคํƒ ์—ฐ์‚ฐ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ, Stack ํด๋ž˜์Šค ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.)

โ†’ ์ž๋ฐ” ์ž์‹ ๋„ "์ด๊ฑด ์ž˜๋ชป ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ์“ฐ์ง€ ๋งˆ์„ธ์š”" ๋ผ๊ณ  ์ธ์ •.

ํ˜„๋Œ€ ์ž๋ฐ”์˜ ๊ถŒ์žฅ ๋ฐฉ์‹:

Deque<String> stack = new ArrayDeque<>();
stack.push("A");
stack.pop();

๐Ÿ“– ์ƒ์†์˜ 4๊ฐ€์ง€ ์น˜๋ช…์  ๋ฌธ์ œ

๋ฌธ์ œ 1: ์บก์Аํ™” ํŒŒ๊ดด โ€” "๋ถ€๋ชจ์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์— ์ž์‹์ด ์˜์กด"

๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์ด ๋ฐ”๋€Œ๋ฉด ์ž์‹์ด ๊นจ์ง.

์˜ˆ์‹œ:

public class CountingArrayList<E> extends ArrayList<E> {
    private int addCount = 0;
    
    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }
    
    @Override
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);  // ๋‚ด๋ถ€์ ์œผ๋กœ add()๋ฅผ ํ˜ธ์ถœํ•จ!
    }
    
    public int getAddCount() { return addCount; }
}

ํ…Œ์ŠคํŠธ:

CountingArrayList<String> list = new CountingArrayList<>();
list.addAll(List.of("A", "B", "C"));

System.out.println(list.getAddCount());  // 6 โŒ (3์ด์–ด์•ผ ํ•˜๋Š”๋ฐ)

์™œ?:

  • addAll() ์ด addCount += 3 ํ›„
  • ๋‚ด๋ถ€์ ์œผ๋กœ add() ๋ฅผ 3๋ฒˆ ํ˜ธ์ถœ โ†’ addCount ๊ฐ€ ๋˜ 3 ์ฆ๊ฐ€
  • ๊ฒฐ๊ณผ: 6

โ†’ ๋ถ€๋ชจ(ArrayList)์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋ชจ๋ฅด๋ฉด ์ž์‹์ด ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ ์•ˆ ํ•จ.
โ†’ ์ž๋ฐ” ๋‹ค์Œ ๋ฒ„์ „์—์„œ ArrayList.addAll() ์˜ ๊ตฌํ˜„์ด ๋ฐ”๋€Œ๋ฉด? ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๊ฐ‘์ž๊ธฐ ๊นจ์ง.

์ด๋ฅผ "์ทจ์•ฝํ•œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ๋ฌธ์ œ (Fragile Base Class Problem)" ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.


๋ฌธ์ œ 2: ๋‹จ์ผ ์ƒ์† ์ œ์•ฝ โ€” "ํ•œ ๋ถ€๋ชจ๋งŒ ๊ฐ€๋Šฅ"

์ž๋ฐ”๋Š” ๋‹ค์ค‘ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค.

public class A { ... }
public class B { ... }
public class C extends A, B { ... }  // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ

์™œ ๋ฌธ์ œ์ธ๊ฐ€:

  • "์ด ํด๋ž˜์Šค๋Š” ๋‘ ๊ฐ€์ง€ ํŠน์„ฑ์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค" ๊ฐ™์€ ์ž์—ฐ์Šค๋Ÿฌ์šด ์š”๊ตฌ๋ฅผ ํ‘œํ˜„ ๋ชป ํ•จ
  • ์ธํ„ฐํŽ˜์ด์Šค๋กœ๋Š” ๊ฐ€๋Šฅ (๋ฉ”์„œ๋“œ ์ •์˜๋งŒ ๊ฐ€๋Šฅ)
  • ํ•ฉ์„ฑ์œผ๋กœ๋Š” ๊ฐ€๋Šฅ (์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ)
// ํ•ฉ์„ฑ์œผ๋กœ๋Š” ์ž์œ ๋กœ์›€
public class C {
    private final A a;
    private final B b;
    // ๋‘ ๊ฐ€์ง€ ๋Šฅ๋ ฅ ๋ชจ๋‘ ํ™œ์šฉ ๊ฐ€๋Šฅ
}

๋ฌธ์ œ 3: ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ โ€” "๋Ÿฐํƒ€์ž„์— ๋ถ€๋ชจ๋ฅผ ๋ชป ๋ฐ”๊ฟˆ"

public class Customer extends NormalCustomer { ... }
// โ†’ ์ด Customer๋Š” ์˜์›ํžˆ NormalCustomer
// โ†’ ๋Ÿฐํƒ€์ž„์— VipCustomer๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์Œ

ํ•ฉ์„ฑ์ด๋ผ๋ฉด ๊ฐ€๋Šฅ:

public class Customer {
    private CustomerLevel level;  // ๋Ÿฐํƒ€์ž„์— ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ
    
    public void upgradeToVip() {
        this.level = new VipLevel();  // ๋“ฑ๊ธ‰ ๋ณ€๊ฒฝ
    }
}

โ†’ ํ˜„์‹ค์˜ ๋ณ€ํ™” (์‚ฌ์šฉ์ž๊ฐ€ ์ผ๋ฐ˜ โ†’ VIP ์Šน๊ธ‰) ๋ฅผ ํ‘œํ˜„ํ•˜๋ ค๋ฉด ํ•ฉ์„ฑ์ด ํ•„์ˆ˜.


๋ฌธ์ œ 4: ์ƒ์† ๊ณ„์ธต์˜ ํญ๋ฐœ

์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ–ˆ๋˜ ๊ณ„์ธต์ด ์ ์  ๊นŠ์–ด์ง‘๋‹ˆ๋‹ค.

Animal
  โ””โ”€ Mammal
       โ””โ”€ Carnivore
            โ””โ”€ Felidae
                 โ””โ”€ Cat
                      โ””โ”€ DomesticCat
                           โ””โ”€ KoreanShortHair

๋ฌธ์ œ:

  • 7๋‹จ๊ณ„ ๊นŠ์ด โ€” ์–ด๋””์„œ ์–ด๋–ค ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ค๋Š”์ง€ ์ถ”์  ์–ด๋ ค์›€
  • ์ค‘๊ฐ„์— ๋ฉ”์„œ๋“œ ํ•˜๋‚˜ ๋ฐ”๊พธ๋ฉด ์˜ํ–ฅ ๋ฒ”์œ„ ํญ๋ฐœ
  • ์ƒˆ ์ข…๋ฅ˜ ์ถ”๊ฐ€ ์‹œ ์–ด๋””์— ๋ผ์›Œ์•ผ ํ• ์ง€ ๊ณ ๋ฏผ (๊ณ ์–‘์ด + ๊ฐ•์•„์ง€ ํ˜ผํ˜ˆ์€?)

๐ŸŽฏ ๊ทธ๋Ÿผ ์–ธ์ œ ์ƒ์†์„ ์จ์•ผ ํ•˜๋‚˜?

์ƒ์†์ด ๋ฌด์กฐ๊ฑด ๋‚˜์œ ๊ฑด ์•„๋‹™๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•œ ๊ธฐ์ค€ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์† ์‚ฌ์šฉ ์ฒดํฌ๋ฆฌ์ŠคํŠธ โœ…

๋‹ค์Œ ๋ชจ๋“  ์กฐ๊ฑด ์„ ๋งŒ์กฑํ•  ๋•Œ๋งŒ ์ƒ์†:

  1. ๋ช…ํ™•ํ•œ is-a ๊ด€๊ณ„์ธ๊ฐ€?

    • "VipCustomer ๋Š” Customer ์ด๋‹ค" โ€” YES โ†’ ์ƒ์† OK
    • "Stack ์€ ArrayList ์ด๋‹ค" โ€” NO โ†’ ์ƒ์† X
  2. ๋ถ€๋ชจ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ธ๊ฐ€?

    • ์•ˆ์ •๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ธํ„ฐํŽ˜์ด์Šค โ€” OK
    • ์ž์ฃผ ๋ฐ”๋€Œ๋Š” ๋‚ด๋ถ€ ๊ตฌํ˜„ โ€” NO
  3. ์ž์‹์ด ๋ถ€๋ชจ์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์˜๋ฏธ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜?

    • VipCustomer๋Š” Customer์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ OK
    • Stack์€ ArrayList์˜ add(int, E) ๋ฅผ ์˜๋ฏธ ์žˆ๊ฒŒ ์‚ฌ์šฉ X โ†’ ์ƒ์† X
  4. ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๊ฐ€ ์˜๊ตฌ์ ์ธ๊ฐ€?

    • VipCustomer๋Š” ์˜์›ํžˆ Customer โ€” OK
    • ๋“ฑ๊ธ‰์ด ๋ฐ”๋€Œ๋Š” ๊ฑฐ๋ผ๋ฉด โ€” NO (ํ•ฉ์„ฑ์ด ๋‹ต)
  5. "๊ณตํ†ต ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ" ์ด ๋ชฉ์ ์ธ๊ฐ€?

    • YES โ†’ โŒ ์ž˜๋ชป๋œ ๋™๊ธฐ โ†’ ํ•ฉ์„ฑ ์‚ฌ์šฉ
    • NO, ์ง„์งœ is-a ๊ด€๊ณ„ โ†’ ์ƒ์† OK

์‹ค๋ฌด์—์„œ ์ƒ์†์ด ์ ํ•ฉํ•œ ์‚ฌ๋ก€

1. ์ถ”์ƒ ํด๋ž˜์Šค + Template Method ํŒจํ„ด

public abstract class Report {
    public final void generate() {  // ํ๋ฆ„ ๊ณ ์ •
        loadData();
        format();
        save();
    }
    
    protected abstract void loadData();
    protected abstract void format();
    protected abstract void save();
}

public class FareReport extends Report { ... }
public class CustomerReport extends Report { ... }

โ†’ "Report์˜ ํ•œ ์ข…๋ฅ˜๋‹ค" + ํ๋ฆ„ ๊ณตํ†ตํ™” โ†’ ์ƒ์† OK.

2. ๋ช…ํ™•ํ•œ ๋„๋ฉ”์ธ ๊ณ„์ธต

public abstract class Customer {
    // ๊ณตํ†ต ์†์„ฑ๊ณผ ํ–‰๋™
}

public class IndividualCustomer extends Customer { ... }
public class CorporateCustomer extends Customer { ... }

โ†’ ์ง„์งœ is-a ๊ด€๊ณ„ โ†’ ์ƒ์† OK.

3. ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ™•์žฅ ํฌ์ธํŠธ

public class MyController extends AbstractController { ... }
public class CustomFilter extends OncePerRequestFilter { ... }

โ†’ Spring์ด ์˜๋„ํ•œ ํ™•์žฅ ๋ฐฉ์‹ โ†’ ์ƒ์† OK.


๐Ÿ”„ ์ƒ์†์„ ํ•ฉ์„ฑ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๋ฐฉ๋ฒ•

์ด๋ฏธ ๋งŒ๋“  ์ƒ์† ์ฝ”๋“œ๋ฅผ ํ•ฉ์„ฑ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ํŒจํ„ด.

Before โ€” ์ƒ์†

public class CountingArrayList<E> extends ArrayList<E> {
    private int addCount = 0;
    
    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }
    
    @Override
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);  // ๋ถ€๋ชจ ๋‚ด๋ถ€ ๊ตฌํ˜„ ์˜์กด
    }
    
    public int getAddCount() { return addCount; }
}

After โ€” ํ•ฉ์„ฑ (Wrapper / Decorator ํŒจํ„ด)

public class CountingList<E> {
    private final List<E> delegate;  // ๊ฐ€์ง (has-a)
    private int addCount = 0;
    
    public CountingList(List<E> delegate) {
        this.delegate = delegate;
    }
    
    public boolean add(E e) {
        addCount++;
        return delegate.add(e);
    }
    
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return delegate.addAll(c);  // ๋ถ€๋ชจ ๋‚ด๋ถ€ ๊ตฌํ˜„ ๋ฌด๊ด€
    }
    
    public int getAddCount() { return addCount; }
    
    // ํ•„์š”ํ•œ List ๋ฉ”์„œ๋“œ๋งŒ ์œ„์ž„
    public E get(int index) { return delegate.get(index); }
    public int size() { return delegate.size(); }
    // ...
}

ํšจ๊ณผ:

  • ArrayList์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„ ๋ณ€๊ฒฝ์— ์˜ํ–ฅ X
  • ArrayList๋“  LinkedList๋“  ์ž์œ ๋กญ๊ฒŒ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
  • ๋…ธ์ถœํ•  ๋ฉ”์„œ๋“œ๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ๋…ธ์ถœ
CountingList<String> list = new CountingList<>(new ArrayList<>());
// ๋˜๋Š”
CountingList<String> list = new CountingList<>(new LinkedList<>());  // ๋‹ค๋ฅธ ๊ตฌํ˜„๋„ OK

๐Ÿ—๏ธ ILIC ์šด์ž„ ์‹œ์Šคํ…œ์—์„œ์˜ ์ ์šฉ

์ž˜๋ชป๋œ ์˜ˆ โ€” ์ƒ์† ๋‚จ์šฉ

ILIC ์šด์ž„์˜ Customer ๋“ฑ๊ธ‰๋ณ„ ๊ณ„์‚ฐ์„ ์ƒ์†์œผ๋กœ:

public class Customer {
    protected String name;
    protected String email;
    
    public int calculateDiscount(int amount) { return 0; }
}

public class VipCustomer extends Customer {
    @Override
    public int calculateDiscount(int amount) { return amount * 20 / 100; }
}

public class PartnerCustomer extends Customer {
    @Override
    public int calculateDiscount(int amount) { return amount * 30 / 100; }
}

๋ฌธ์ œ:

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ผ๋ฐ˜ โ†’ VIP ์Šน๊ธ‰ํ•˜๋ฉด? ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•จ
  • ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ๋“ฑ๊ธ‰์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด? (์˜ˆ: ์นด๋“œ ๋“ฑ๊ธ‰ + ๋ฉค๋ฒ„์‹ญ ๋“ฑ๊ธ‰)
  • ๋“ฑ๊ธ‰ ์ •์ฑ…์ด ์ž์ฃผ ๋ฐ”๋€๋‹ค๋ฉด? ์ƒˆ ํด๋ž˜์Šค ๋งค๋ฒˆ ์ƒ์„ฑ

์ข‹์€ ์˜ˆ โ€” ํ•ฉ์„ฑ

// ๋“ฑ๊ธ‰์€ ์ •์ฑ… ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌ
public interface DiscountPolicy {
    int calculate(int amount);
}

public class NoDiscountPolicy implements DiscountPolicy {
    public int calculate(int amount) { return 0; }
}

public class VipDiscountPolicy implements DiscountPolicy {
    public int calculate(int amount) { return amount * 20 / 100; }
}

public class PartnerDiscountPolicy implements DiscountPolicy {
    public int calculate(int amount) { return amount * 30 / 100; }
}

// Customer๋Š” ์ •์ฑ…์„ "๊ฐ€์ง" (has-a)
public class Customer {
    private String name;
    private String email;
    private DiscountPolicy discountPolicy;  // ๊ฐ€์ง
    
    public int calculateDiscount(int amount) {
        return discountPolicy.calculate(amount);
    }
    
    public void changeDiscountPolicy(DiscountPolicy newPolicy) {  // ๋Ÿฐํƒ€์ž„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
        this.discountPolicy = newPolicy;
    }
}

ํšจ๊ณผ:

  • ์ผ๋ฐ˜ โ†’ VIP ์Šน๊ธ‰: customer.changeDiscountPolicy(new VipDiscountPolicy()) โ† ๊ฐ์ฒด ๊ทธ๋Œ€๋กœ
  • ์ƒˆ ์ •์ฑ… (์‹œ์ฆŒ ํ• ์ธ): ์ƒˆ DiscountPolicy ๊ตฌํ˜„์ฒด 1๊ฐœ๋งŒ ์ถ”๊ฐ€
  • A/B ํ…Œ์ŠคํŠธ, ์ž„์‹œ ์ •์ฑ… ๋“ฑ ์œ ์—ฐ์„ฑ ํญ๋ฐœ

โ†’ ์ด๊ฒŒ 17์ฃผ์ฐจ Spring Strategy Pattern๊ณผ ์ง๊ฒฐ๋˜๋Š” ์‚ฌ๊ณ ๋ฐฉ์‹.


โš–๏ธ ์ƒ์† vs ํ•ฉ์„ฑ ๊ฒฐ์ • ํŠธ๋ฆฌ

[์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค]
        โ†“
"์ด๊ฑด ๋ช…ํ™•ํžˆ ๋ถ€๋ชจ์˜ ํ•œ ์ข…๋ฅ˜์ธ๊ฐ€?" (is-a)
        โ†“
   YES โ”€โ†’ ์ƒ์† ๊ฒ€ํ† 
   |       โ†“
   |    "๋ถ€๋ชจ๊ฐ€ ์•ˆ์ •์ ์ด๊ณ  ๋ณ€ํ•˜์ง€ ์•Š๋Š”๊ฐ€?"
   |       โ†“
   |    YES โ”€โ†’ ์ƒ์† OK
   |    NO  โ”€โ†’ ํ•ฉ์„ฑ์œผ๋กœ
   |
   NO โ”€โ”€โ†’ ํ•ฉ์„ฑ (has-a)

ํ•œ ์ค„ ๊ฒฐ์ •:

ํ™•์‹ ์ด ์—†์œผ๋ฉด ํ•ฉ์„ฑ. ์ž˜๋ชป๋œ ํ•ฉ์„ฑ์€ ์ˆ˜์ •์ด ์‰ฝ์ง€๋งŒ, ์ž˜๋ชป๋œ ์ƒ์†์€ ์ˆ˜์ •์ด ๋งค์šฐ ์–ด๋ ต๋‹ค.


๐ŸŽ“ ๊ฑฐ์žฅ๋“ค์˜ ๊ฒฉ์–ธ

Joshua Bloch (Effective Java ์ €์ž)

"์ƒ์†์€ ์บก์Аํ™”๋ฅผ ์œ„๋ฐ˜ํ•œ๋‹ค. ์ƒ์† ๋Œ€์‹  ํ•ฉ์„ฑ์„ ์‚ฌ์šฉํ•˜๋ผ."

GoF (Design Patterns ์ €์ž๋“ค)

"ํด๋ž˜์Šค ์ƒ์†๋ณด๋‹ค ๊ฐ์ฒด ํ•ฉ์„ฑ์„ ์„ ํ˜ธํ•˜๋ผ."

Uncle Bob (Clean Code ์ €์ž)

"์ƒ์†์€ ๊ฐ€์žฅ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ์ด๋‹ค. ๊ฐ€๋Šฅํ•œ ์•ฝํ•˜๊ฒŒ ๊ฒฐํ•ฉํ•˜๋ผ."

โ†’ ์†Œํ”„ํŠธ์›จ์–ด ๊ฑฐ์žฅ๋“ค์˜ ์ผ๊ด€๋œ ๋ฉ”์‹œ์ง€: ์ƒ์†์„ ์กฐ์‹ฌํ•˜๋ผ.


ํ•œ ๋ฌธ์žฅ ์š”์•ฝ

์ƒ์†์€ "์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋„๊ตฌ" ๊ฐ€ ์•„๋‹ˆ๋ผ "is-a ๊ด€๊ณ„ ์„ ์–ธ" ์ด๋‹ค.

"๊ณตํ†ต ์ฝ”๋“œ ์“ฐ๊ณ  ์‹ถ์–ด์„œ" ๋ผ๋Š” ๋™๊ธฐ๋กœ ์ƒ์†์„ ์“ฐ๋ฉด ์บก์Аํ™” ํŒŒ๊ดด, ์ทจ์•ฝํ•œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค, ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€, ๋‹จ์ผ ์ƒ์† ์ œ์•ฝ ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ™•์‹ ์ด ์—†์œผ๋ฉด ํ•ฉ์„ฑ โ€” ์ด๊ฒŒ ํ˜„๋Œ€ ์ž๋ฐ”์˜ ํ™ฉ๊ธˆ๋ฅ ์ด๋‹ค.


์‹ค์ˆ˜ 3: God Class (์‹  ํด๋ž˜์Šค)

"ํ•œ ํด๋ž˜์Šค๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ๊ฐ€์ง"

public class FareManager {  // โŒ ๋ชจ๋“  ๊ฑธ ๋‹ค ํ•จ
    public void createFare(...) { }
    public void deleteFare(...) { }
    public void calculateDiscount(...) { }
    public void sendNotification(...) { }
    public void generateReport(...) { }
    public void backupData(...) { }
    public void validateUser(...) { }
    // ... 50๊ฐœ ๋ฉ”์„œ๋“œ
}

์™œ ๋ฌธ์ œ:

  • ํ•œ ๊ณณ์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ๋ณ€ํ™” โ†’ ์ˆ˜์ • ์‹œ ์˜ํ–ฅ ๋ฒ”์œ„ ํผ
  • ํ…Œ์ŠคํŠธ ๋ถˆ๊ฐ€๋Šฅ
  • ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP) ์œ„๋ฐ˜ (Phase 3์—์„œ)

ํ•ด๊ฒฐ:

  • ์ฑ…์ž„๋ณ„๋กœ ๋ถ„๋ฆฌ: FareService, NotificationService, ReportService...

์‹ค์ˆ˜ 4: ์บก์Аํ™” ์œ„๋ฐ˜ (public ํ•„๋“œ)

public class Fare {
    public int amount;  // โŒ ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ˆ˜์ • ๊ฐ€๋Šฅ
}

์™œ ์œ„ํ—˜:

  • ๋ˆ„๊ตฌ๋‚˜ ๋ฌด๊ฒฐ์„ฑ ๊นจ๋œจ๋ฆผ
  • ๋ณ€๊ฒฝ ์‹œ ์ถ”์  ๋ถˆ๊ฐ€

ํ•ด๊ฒฐ: private + ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•œ ์ ‘๊ทผ


์‹ค์ˆ˜ 5: ๊ฐ์ฒด์ง€ํ–ฅ์ด ๋งŒ๋Šฅ์ด๋ผ๋Š” ์ฐฉ๊ฐ

๊ฐ์ฒด์ง€ํ–ฅ์ด ํ•ญ์ƒ ์ข‹์€ ๊ฑด ์•„๋‹ˆ๋‹ค โš ๏ธ

๊ฐ์ฒด์ง€ํ–ฅ์ด ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ:

  • ๋‹จ์ˆœ ์Šคํฌ๋ฆฝํŠธ (50์ค„ ๋ฏธ๋งŒ)
  • ์ˆ˜ํ•™ ๊ณ„์‚ฐ ์œ„์ฃผ (ํ•จ์ˆ˜ํ˜•์ด ๋” ๋‚˜์Œ)
  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ํŒŒ์ดํ”„๋ผ์ธ (์ŠคํŠธ๋ฆผ์ด ๋” ๋‚˜์Œ)

ํ˜„๋Œ€ ํŠธ๋ Œ๋“œ:

  • ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„ โ€” ๊ฐ์ฒด์ง€ํ–ฅ + ํ•จ์ˆ˜ํ˜• + ์ ˆ์ฐจ์  ํ˜ผํ•ฉ
  • ์ž๋ฐ”๋„ ํ•จ์ˆ˜ํ˜• ์š”์†Œ ์ถ”๊ฐ€ (Stream, Lambda โ€” 3์ฃผ์ฐจ)
  • "๋„๊ตฌ๋กœ ๋ด์•ผ์ง€ ์ข…๊ต๋กœ ๋ณด๋ฉด ์•ˆ ๋จ"

๐Ÿ”— 8. ์—ฐ๊ด€ ๊ฐœ๋… ๋งต

์ด Unit์ด ๋‹ค๋ฅธ ๊ฐœ๋…๊ณผ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ๋ณธ๋‹ค.

์ง์ ‘ ์ด์–ด์ง€๋Š” ํ•™์Šต

[Unit 1.1: ์ ˆ์ฐจ์ง€ํ–ฅ vs ๊ฐ์ฒด์ง€ํ–ฅ]  โ† ์ง€๊ธˆ ์—ฌ๊ธฐ
        โ†“
[Unit 1.2: ํด๋ž˜์Šค์™€ ๊ฐ์ฒด์˜ ๋ณธ์งˆ] โ€” ๋‹ค์Œ ํ•™์Šต
        โ†“
[Phase 2: ํด๋ž˜์Šค ๋ฌธ๋ฒ•๊ณผ ๊ฐ์ฒด๊ฐ„ ๊ด€๊ณ„]
        โ†“
[Phase 3: SOLID โ€” OOP๋ฅผ ๋ง๊ฐ€๋œจ๋ฆฌ์ง€ ์•Š๋Š” 5๊ณ„๋ช…]

์ด Unit์˜ ๊ฐœ๋…์ด ํ™œ์šฉ๋˜๋Š” ๊ณณ

1์ฃผ์ฐจ ๋‚ด:

  • Phase 4 (JVM ๋ฉ”๋ชจ๋ฆฌ): ๊ฐ์ฒด๊ฐ€ Heap์—, ๋ฉ”์„œ๋“œ๊ฐ€ Method Area์— ์œ„์น˜
  • Phase 5 (GC): ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์†Œ๋ฉธ ๊ด€๋ฆฌ

๋ฏธ๋ž˜ ์ฃผ์ฐจ:

  • 3์ฃผ์ฐจ (์ œ๋„ค๋ฆญ/์ปฌ๋ ‰์…˜): ๋‹คํ˜•์„ฑ์„ ํƒ€์ž…์— ์ ์šฉ
  • 5์ฃผ์ฐจ (Spring IoC): ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์˜์กด์„ฑ ๋ถ„๋ฆฌ ์‘์šฉ
  • 8-9์ฃผ์ฐจ (AOP): ์บก์Аํ™”์˜ ํ•œ๊ณ„๋ฅผ ๋ณด์™„ํ•˜๋Š” ๊ธฐ์ˆ 
  • 11-12์ฃผ์ฐจ (JPA): ๊ฐ์ฒด์™€ RDB์˜ ๋งคํ•‘ (Object-Relational Mapping)

4๋Œ€ ์›์น™๊ณผ SOLID์˜ ๊ด€๊ณ„ โญ

[์บก์Аํ™”] โ”€โ”€โ”€โ”€โ”€โ†’ [SRP] (๋‹จ์ผ ์ฑ…์ž„)
              [DIP] (์˜์กด ์—ญ์ „)

[์ƒ์†] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ [LSP] (๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜)
              [ISP] (์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ)

[๋‹คํ˜•์„ฑ] โ”€โ”€โ”€โ”€โ”€โ†’ [OCP] (๊ฐœ๋ฐฉ-ํ์‡„)
              [DIP] (์˜์กด ์—ญ์ „)

[์ถ”์ƒํ™”] โ”€โ”€โ”€โ”€โ”€โ†’ ๊ฑฐ์˜ ๋ชจ๋“  SOLID ์›์น™

โ†’ SOLID๋Š” 4๋Œ€ ์›์น™์„ ์ž˜ ์“ฐ๊ธฐ ์œ„ํ•œ 5๊ฐ€์ง€ ๊ทœ์น™.


๊ฐ์ฒด์ง€ํ–ฅ โ†’ ํ•จ์ˆ˜ํ˜• โ†’ ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„

[1960s] ์ ˆ์ฐจ์ง€ํ–ฅ (C)
        โ†“
[1990s] ๊ฐ์ฒด์ง€ํ–ฅ (Java) โญ ์šฐ๋ฆฌ๊ฐ€ ํ•™์Šต ์ค‘
        โ†“
[2000s] ํ•จ์ˆ˜ํ˜• ๋ถ€ํ™œ (Scala, Haskell)
        โ†“
[2010s] ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„ (Kotlin, Modern Java)
        โ†“
[2020s+] ๋„๊ตฌ๋ณ„ ์ ์žฌ์ ์†Œ ์‚ฌ์šฉ

์ž๋ฐ”๋„ 8๋ฒ„์ „๋ถ€ํ„ฐ ํ•จ์ˆ˜ํ˜• ์š”์†Œ (Lambda, Stream) ์ถ”๊ฐ€ โ€” 3์ฃผ์ฐจ์—์„œ ํ•™์Šต.


๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ ๋งคํ•‘

์งˆ๋ฌธ์ด Unit์—์„œ์˜ ๋‹ต
"๊ฐ์ฒด์ง€ํ–ฅ์ด ๋ญ”๊ฐ€์š”?"๋ฐ์ดํ„ฐ์™€ ํ–‰๋™์„ ๊ฐ์ฒด๋กœ ๋ฌถ๊ณ  4๋Œ€ ์›์น™์œผ๋กœ ๊ด€๋ฆฌ
"๊ฐ์ฒด์ง€ํ–ฅ์˜ 4๋Œ€ ์›์น™์€?"์บก์Аํ™”, ์ƒ์†, ๋‹คํ˜•์„ฑ, ์ถ”์ƒํ™”
"์™œ ๊ฐ์ฒด์ง€ํ–ฅ์„ ์“ฐ๋‚˜์š”?"ํฐ ์‹œ์Šคํ…œ์—์„œ ์œ ์ง€๋ณด์ˆ˜/ํ™•์žฅ/์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด
"์ ˆ์ฐจ์ง€ํ–ฅ๊ณผ ์ฐจ์ด๋Š”?"๋ฐ์ดํ„ฐ-ํ•จ์ˆ˜ ๋ถ„๋ฆฌ vs ๊ฐ์ฒด๋กœ ๋ฌถ์Œ, ๊ทธ๋กœ ์ธํ•œ if ์ง€์˜ฅ vs ๋‹คํ˜•์„ฑ

๐Ÿ“ 9. ํ•ต์‹ฌ ์š”์•ฝ โ€” 3์ค„ ์ •๋ฆฌ

1๏ธโƒฃ ๊ฐ์ฒด์ง€ํ–ฅ์€ "ํฐ ์‹œ์Šคํ…œ์˜ ๋ณต์žก๋„"๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ํŒจ๋Ÿฌ๋‹ค์ž„์ด๋‹ค.

์ ˆ์ฐจ์ง€ํ–ฅ์ด ํ‹€๋ฆฐ ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ฝ”๋“œ๊ฐ€ ์ปค์ง€๋ฉด์„œ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑยทํ™•์žฅ์„ฑยท์žฌ์‚ฌ์šฉ์„ฑ์— ํ•œ๊ณ„๊ฐ€ ๋“œ๋Ÿฌ๋‚ฌ๊ณ , ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ์™€ ํ–‰๋™์„ ๊ฐ์ฒด ๋ผ๋Š” ๋‹จ์œ„๋กœ ๋ฌถ๋Š” ์‚ฌ๊ณ ๋ฐฉ์‹์ด ๋“ฑ์žฅํ–ˆ๋‹ค.

2๏ธโƒฃ 4๋Œ€ ์›์น™(์บก์ƒ๋‹ค์ถ”)์„ ์ง€ํ‚ฌ ๋•Œ๋งŒ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ๊ฐ€์น˜๊ฐ€ ์‚ด์•„๋‚œ๋‹ค.

์บก์Аํ™”(๋ฐ์ดํ„ฐ ๋ณดํ˜ธ), ์ƒ์†(๊ณตํ†ต ์ถ”์ถœ), ๋‹คํ˜•์„ฑ(if ์ง€์˜ฅ ํ•ด๊ฒฐ), ์ถ”์ƒํ™”(๋ณธ์งˆ๋งŒ ๋…ธ์ถœ) โ€” ์ด ๋„ค ๊ฐ€์ง€๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•  ๋•Œ "์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ ์•ˆ ๊ฑด๋“œ๋ฆฌ๊ธฐ" ๊ฐ™์€ ๋งˆ๋ฒ•์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋นˆํ˜ˆ ๋ชจ๋ธยทGod Class ๊ฐ™์€ ์•ˆํ‹ฐํŒจํ„ด์€ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ํƒˆ๋งŒ ์“ด ์ ˆ์ฐจ์ง€ํ–ฅ์ด๋‹ค.

3๏ธโƒฃ ๊ฐ์ฒด์ง€ํ–ฅ์€ ๋„๊ตฌ๋‹ค โ€” ๋ชจ๋“  ๊ณณ์— ์“ฐ๋ฉด ์•ˆ ๋œ๋‹ค.

ํฐ ์‹œ์Šคํ…œยทํ˜‘์—…ยท์žฅ๊ธฐ ์œ ์ง€๋ณด์ˆ˜์—๋Š” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋‹จ์ˆœ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ์ˆ˜ํ•™ ๊ณ„์‚ฐ์—๋Š” ๊ณผํ•œ ๋„๊ตฌ๋‹ค. ์ž๋ฐ”๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋˜ ํ•จ์ˆ˜ํ˜•(Lambda, Stream)๋„ ํก์ˆ˜ํ•œ ๋‹ค์ค‘ ํŒจ๋Ÿฌ๋‹ค์ž„ ์–ธ์–ด ๋กœ ์ง„ํ™” ์ค‘์ด๋‹ค. ์ ์žฌ์ ์†Œ๊ฐ€ ํ•ต์‹ฌ.


๐ŸŽ“ ํ•™์Šต ์ž๊ธฐ ์ ๊ฒ€

๊ธฐ๋ณธ ์ดํ•ด

  • ์ ˆ์ฐจ์ง€ํ–ฅ๊ณผ ๊ฐ์ฒด์ง€ํ–ฅ์˜ ๊ฒฐ์ •์  ์ฐจ์ด๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๊ฐ์ฒด์ง€ํ–ฅ 4๋Œ€ ์›์น™์˜ ์ด๋ฆ„์„ ์™ธ์šธ ์ˆ˜ ์žˆ๋‹ค (์บก์ƒ๋‹ค์ถ”)
  • ๊ฐ ์›์น™์ด ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š”์ง€ 1์ค„๋กœ ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค

์‹ค์ „ ์ ์šฉ

  • ILIC ์ฝ”๋“œ์—์„œ ๋นˆํ˜ˆ ๋ชจ๋ธ์ธ ํด๋ž˜์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค
  • if ์ง€์˜ฅ์„ ๋‹คํ˜•์„ฑ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค
  • "์ƒˆ ๋“ฑ๊ธ‰ ์ถ”๊ฐ€ ์‹œ ๋ฌด์—‡์„ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š”๊ฐ€" ๋ฅผ ์ ˆ์ฐจ์ง€ํ–ฅ/๊ฐ์ฒด์ง€ํ–ฅ ๋‘ ๋ฒ„์ „์œผ๋กœ ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค

๋ฉด์ ‘ ๋Œ€๋น„ (5๋ถ„ ๋‹ต๋ณ€)

  • "๊ฐ์ฒด์ง€ํ–ฅ์ด ๋ญ”๊ฐ€์š”?" ์— 5๋ถ„ ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "์™œ ๊ฐ์ฒด์ง€ํ–ฅ์„ ์‚ฌ์šฉํ•˜๋‚˜์š”?" ์— ILIC ์‚ฌ๋ก€๋ฅผ ๋“ค์–ด ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "๊ฐ์ฒด์ง€ํ–ฅ์˜ ํ•œ๊ณ„๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?" ์— ๊ท ํ˜• ์žกํžŒ ๋‹ต๋ณ€ ๊ฐ€๋Šฅ

๋‹ค์Œ Unit์œผ๋กœ

  • ํด๋ž˜์Šค์™€ ๊ฐ์ฒด์˜ ๋ณธ์งˆ ์„ ํ•™์Šตํ•  ์ค€๋น„ ์™„๋ฃŒ
  • "ํด๋ž˜์Šค๋Š” ์ฒญ์‚ฌ์ง„, ๊ฐ์ฒด๋Š” ์ธ์Šคํ„ด์Šค" ๋ผ๋Š” ํ‘œํ˜„์ด ์–ด๋–ค ์˜๋ฏธ์ธ์ง€ ๊ถ๊ธˆํ•˜๋‹ค

profile
Software Developer

0๊ฐœ์˜ ๋Œ“๊ธ€