๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Java

[Java] Composition vs Inheritance โ€” ์–ธ์ œ ์จ์•ผ ํ•˜๋‚˜?

by clolee 2025. 4. 2.
๐Ÿง  Composition vs Inheritance โ€” ์–ธ์ œ ์จ์•ผ ํ•˜๋‚˜?

โœ… 1. ๊ธฐ๋ณธ ๊ฐœ๋… ์ •๋ฆฌ

๐Ÿ“Œ Inheritance (์ƒ์†)

  • "is-a" ๊ด€๊ณ„์ผ ๋•Œ ์‚ฌ์šฉ
  • ํ•œ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›์•„ ํ™•์žฅ
  • ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ํ˜•์„ฑํ•˜๋ฉฐ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์— ์œ ๋ฆฌ

  
class Animal {
void eat() { System.out.println("eating..."); }
}
class Dog extends Animal {
void bark() { System.out.println("bark!"); }
}

โœ… Dog is-a Animal โ†’ ์˜ฌ๋ฐ”๋ฅธ ์ƒ์†


๐Ÿ“Œ Composition (๊ตฌ์„ฑ)

  • "has-a" ๊ด€๊ณ„์ผ ๋•Œ ์‚ฌ์šฉ
  • ํด๋ž˜์Šค ๋‚ด๋ถ€์— ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•„๋“œ๋กœ ํฌํ•จ์‹œ์ผœ ์‚ฌ์šฉ
  • ์ƒ์†๋ณด๋‹ค ์œ ์—ฐํ•˜๋ฉฐ, ์—ญํ•  ๋ถ„๋ฆฌ์™€ ๊ธฐ๋Šฅ ์กฐํ•ฉ์— ์œ ๋ฆฌ

  
class Engine {
void run() { System.out.println("Engine running"); }
}
class Car {
private Engine engine = new Engine();
void start() {
engine.run(); // Engine์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ
}
}

โœ… Car has-a Engine โ†’ ๊ตฌ์„ฑ ๊ด€๊ณ„


โœ… 2. ์ฐจ์ด์  ์š”์•ฝ

ํ•ญ๋ชฉ Inheritance (์ƒ์†) Composition (๊ตฌ์„ฑ)
๊ด€๊ณ„ is-a has-a
๊ฒฐํ•ฉ๋„ ๋†’์Œ ๋‚ฎ์Œ
์œ ์—ฐ์„ฑ ๋‚ฎ์Œ ๋†’์Œ
ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ ๋‚ฎ์Œ ๋†’์Œ
๋ณ€๊ฒฝ ์˜ํ–ฅ ํผ (๋ถ€๋ชจ ๋ณ€๊ฒฝ ์‹œ ์ž์‹ ์˜ํ–ฅ) ์ž‘์Œ (ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ํฌํ•จ)
์‚ฌ์šฉ ์˜ˆ ํƒ€์ž… ํ™•์žฅ ๊ธฐ๋Šฅ ์กฐํ•ฉ, ์œ„์ž„

โ— 3. โŒ ์–ธ์ œ ์ƒ์†์„ ํ”ผํ•ด์•ผ ํ• ๊นŒ? + โœ… ์–ธ์ œ ์ƒ์†์„ ์จ์•ผ ํ• ๊นŒ?

โŒ ํ”ผํ•ด์•ผ ํ•  ์ƒํ™ฉ๋“ค

โŒ ์˜ˆ1: ๋‹จ์ˆœํžˆ ๊ธฐ๋Šฅ ์žฌ์‚ฌ์šฉ ๋ชฉ์ ์œผ๋กœ๋งŒ ์ƒ์†ํ•  ๋•Œ


  
class FileLogger {
void log(String message) {
System.out.println("LOG: " + message);
}
}
class User extends FileLogger { // โŒ User is-a FileLogger?
String name;
}

๐Ÿ“Œ User๋Š” ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๊ธฐ ์œ„ํ•ด ์ƒ์†์„ ๋ฐ›์•˜์ง€๋งŒ User is-a FileLogger๋Š” ๋ง์ด ์•ˆ ๋จ
โžก๏ธ ์ž˜๋ชป๋œ ์ƒ์†

โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ์‹ (Composition):


  
class User {
String name;
FileLogger logger = new FileLogger();
void doSomething() {
logger.log("User did something");
}
}

โŒ ์˜ˆ2: ๋ถ€๋ชจ ๋ณ€๊ฒฝ ์‹œ ์ž์‹๊นŒ์ง€ ์˜ํ–ฅ ๋ฐ›๋Š” ๊ฒฝ์šฐ


  
class Animal {
void move() {
System.out.println("Animal moves");
}
}
class Snake extends Animal {
// Snake๋Š” ๋ถ€๋ชจ ๋ฉ”์„œ๋“œ๋งŒ ์‚ฌ์šฉ ์ค‘
}

๋ถ€๋ชจ ์ˆ˜์ •:


  
class Animal {
void move() {
// ์ด๋™ ์‹œ ๋กœ๊น… ์ถ”๊ฐ€๋จ
System.out.println("LOG: animal moving...");
}
}

๐Ÿ“Œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ณ€๊ฒฝ์ด ์ž์‹ ํด๋ž˜์Šค ์ „์ฒด์— ์˜ํ–ฅ์„ ๋ฏธ์นจ
โžก๏ธ ์บก์Šํ™” ๊นจ์ง

๋”๋ณด๊ธฐ

๊ทธ ๊ตฌ์กฐ๋ฅผ ์ƒ์† ๋Œ€์‹  ๊ตฌ์„ฑ(Composition)์œผ๋กœ ๋ฐ”๊ฟจ์„ ๋•Œ ์–ด๋–ค ์‹์œผ๋กœ ๋˜๋Š”์ง€


โœ… ์ƒ์† ๊ตฌ์กฐ (๋ฌธ์ œ ์ƒํ™ฉ ๋‹ค์‹œ ๋ณต์Šต)

1. ์ƒ์† ์‹œ ๋ถ€๋ชจ ํด๋ž˜์Šค ๋ณ€๊ฒฝ โ†’ ์ž์‹ ํด๋ž˜์Šค ์˜ํ–ฅ ๋ฐ›๋Š” ์ด์œ 

 

๐Ÿ“Œ ๊ฐœ๋… ์„ค๋ช…

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

์ด๊ฑธ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ(high coupling) ์ด๋ผ๊ณ  ํ•ด์š”.


โ— ๋ฌธ์ œ ์š”์•ฝ

๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์ด ๋ฐ”๋€Œ๋ฉด,
์ž์‹ ํด๋ž˜์Šค๋Š” ์•Œ์ง€ ๋ชปํ•œ ์ฑ„ ๊ทธ ์˜ํ–ฅ์„ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š”๋‹ค.

 

๐Ÿ’ก ์˜ˆ์ œ ์„ค๋ช…


  
class Animal {
void move() {
System.out.println("Animal moves");
}
}
class Snake extends Animal {
// ์•„๋ฌด ๊ฒƒ๋„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ์•ˆ ํ•จ โ†’ Animal์˜ move() ์‚ฌ์šฉ
}

 

๐Ÿ’ฅ ๊ทธ๋Ÿฐ๋ฐ Animal์˜ ๋‚ด๋ถ€๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ...


  
class Animal {
void move() {
logGPS(); // ์˜ˆ: ์ถ”๊ฐ€๋œ ๋กœ๊น… ๊ธฐ๋Šฅ (์„ฑ๋Šฅ ์ €ํ•˜ ๊ฐ€๋Šฅ์„ฑ)
System.out.println("Animal moves");
}
}

 

โ— ๋ฌธ์ œ


  
Snake s = new Snake();
s.move(); // ์ถœ๋ ฅ: Animal moves with tracking
// โ†’ ์˜๋„์น˜ ์•Š๊ฒŒ GPS ๋กœ๊ทธ ๊ธฐ๋Šฅ๊นŒ์ง€ ๋”ฐ๋ผ์˜ด
  • Snake๋Š” move() ๋‚ด๋ถ€๊ฐ€ ๋ณ€๊ฒฝ๋œ ์‚ฌ์‹ค๋„ ๋ชจ๋ฅด๊ณ  ๋”ฐ๋ผ์˜ด
  • ํ…Œ์ŠคํŠธ๋„ ์˜ˆ์™ธ ์—†์ด ์˜ํ–ฅ๋ฐ›๊ณ , ์„ฑ๋Šฅ ๋ฌธ์ œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

๐Ÿ” ์š”์•ฝ: ์ƒ์†์€ ๋‚ด๋ถ€ ๊ตฌํ˜„๊นŒ์ง€ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜๋ฏ€๋กœ, ๋ถ€๋ชจ ๋ณ€๊ฒฝ์ด ์ž์‹์—๊ฒŒ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋œ๋‹ค.

โžก๏ธ ์ด๋Ÿฐ ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด ๊ตฌ์„ฑ(Composition)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์•ˆ์ „ํ•˜๋‹ค.


โœ… ๊ตฌ์„ฑ(Composition) ๊ตฌ์กฐ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉด?


  
class AnimalMover {
void move() {
System.out.println("Animal moves");
}
}
class Snake {
private AnimalMover mover = new AnimalMover();
void move() {
mover.move();
}
}

๐Ÿ”„ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉดโ€ฆ

  • Snake๋Š” AnimalMover ๊ฐ์ฒด๋ฅผ "๊ฐ€์ง€๊ณ " ์žˆ์–ด์š” (has-a ๊ด€๊ณ„)
  • AnimalMover๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„, Snake๋Š” ์„ ํƒ์ ์œผ๋กœ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์–ด์š”

โœ… ๊ตฌ์„ฑ์˜ ํ•ต์‹ฌ ์žฅ์ : ์œ ์—ฐํ•˜๊ฒŒ ๊ต์ฒด ๊ฐ€๋Šฅ!


  
class AnimalMoverWithLogging extends AnimalMover {
@Override
void move() {
logGPS(); // ์„ฑ๋Šฅ ๋น„์šฉ์ด ํฐ ๊ธฐ๋Šฅ
super.move();
}
}

  
Snake snake = new Snake();
snake.setMover(new AnimalMoverWithLogging()); // ์ „๋žต ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

โžก๏ธ ๋Ÿฐํƒ€์ž„์— ์–ด๋–ค mover๋ฅผ ์“ธ์ง€ ๊ต์ฒด ๊ฐ€๋Šฅ โ†’ ์ „๋žต ํŒจํ„ด ์‘์šฉ ๊ฐ€๋Šฅ


โœ… ์ „์ฒด ์ฝ”๋“œ ์˜ˆ์‹œ (๋ฆฌํŒฉํ† ๋ง ๋ฒ„์ „)


  
// ์›€์ง์ž„์„ ๋‹ด๋‹นํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ
class AnimalMover {
void move() {
System.out.println("Animal moves");
}
}
// ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ ์ „๋žต
class AnimalMoverWithLogging extends AnimalMover {
@Override
void move() {
logGPS();
super.move();
}
private void logGPS() {
System.out.println("[GPS ๋กœ๊ทธ]: ์œ„์น˜ ๊ธฐ๋ก๋จ");
}
}
// Snake๋Š” Animal์ด ์•„๋‹Œ ๋ณ„๋„ ํด๋ž˜์Šค โ†’ ๊ตฌ์„ฑ ์‚ฌ์šฉ
class Snake {
private AnimalMover mover;
Snake(AnimalMover mover) {
this.mover = mover;
}
void move() {
mover.move(); // ๋™์ž‘ ์œ„์ž„
}
void setMover(AnimalMover newMover) {
this.mover = newMover; // ์ „๋žต ๊ต์ฒด๋„ ๊ฐ€๋Šฅ
}
}

โœ… ์‹คํ–‰ ์˜ˆ์‹œ


  
public class Main {
public static void main(String[] args) {
Snake snake = new Snake(new AnimalMover());
snake.move();
// ์ถœ๋ ฅ: Animal moves
// ๋™์ž‘ ์ „๋žต ๊ต์ฒด
snake.setMover(new AnimalMoverWithLogging());
snake.move();
// ์ถœ๋ ฅ:
// [GPS ๋กœ๊ทธ]: ์œ„์น˜ ๊ธฐ๋ก๋จ
// Animal moves
}
}

โœ… ๊ตฌ์„ฑ์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์ƒ๊ธฐ๋Š” ์žฅ์ 

ํ•ญ๋ชฉ  ์„ค๋ช…
์œ ์—ฐ์„ฑ ํ•„์š”ํ•  ๋•Œ ๋™์ž‘์„ ๊ต์ฒด ๊ฐ€๋Šฅ (์˜ˆ: ํ…Œ์ŠคํŠธ์šฉ, ์„ฑ๋Šฅ ์ œํ•œ์šฉ ๋“ฑ)
ํ…Œ์ŠคํŠธ์„ฑ ๊ฐ€์งœ mover ๋„ฃ์–ด์„œ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ (MockMover)
๊ฒฐํ•ฉ๋„ ๋‚ฎ์Œ Snake๋Š” mover์˜ ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กด
์žฌ์‚ฌ์šฉ์„ฑ AnimalMover๋ฅผ ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ๋„ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
๋ณ€๊ฒฝ ์•ˆ์ „์„ฑ ๋ถ€๋ชจ ํด๋ž˜์Šค ๋ณ€ํ™”์— ์ž๋™์œผ๋กœ ์˜ํ–ฅ๋ฐ›์ง€ ์•Š์Œ

๐Ÿง  ๊ฒฐ๋ก 

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

 


โŒ ์˜ˆ3: ํ…Œ์ŠคํŠธ ์–ด๋ ค์›€ (์ƒ์† ๊นŠ์ด๋กœ ์ธํ•ด)


  
class UserService extends DatabaseService {
void registerUser() {
// DB ์—ฐ๊ฒฐ๋ถ€ํ„ฐ ๊ฐ•์ œ๋กœ ํฌํ•จ๋จ
}
}

โœ… ๊ตฌ์„ฑ์œผ๋กœ ๋Œ€์ฒด:


  
class UserService {
private DatabaseService db;
UserService(DatabaseService db) {
this.db = db; // ์˜์กด์„ฑ ์ฃผ์ž…
}
}

โžก๏ธ ์œ ๋‹› ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ, ์œ ์—ฐ์„ฑ โ†‘


โœ… ๊ทธ๋Ÿผ ์–ธ์ œ ์ƒ์†์„ ์จ์•ผ ํ• ๊นŒ?

โœ… ์˜ˆ1: ์ง„์งœ is-a ๊ด€๊ณ„์ผ ๋•Œ


  
class Vehicle {
void move() { System.out.println("Vehicle moving"); }
}
class Bus extends Vehicle {
void openDoors() { System.out.println("Doors opened"); }
}

โžก๏ธ Bus is-a Vehicle โ†’ ๋…ผ๋ฆฌ์  ํƒ€์ž… ํ™•์žฅ์œผ๋กœ ์ ์ ˆ


โœ… ์˜ˆ2: ๊ธฐ๋ณธ ๋™์ž‘์„ ํ™•์žฅํ•˜๊ณ  ์‹ถ์„ ๋•Œ


  
class Button {
void click() {
System.out.println("Button clicked");
}
}
class AnimatedButton extends Button {
@Override
void click() {
super.click();
System.out.println("...with animation");
}
}

โžก๏ธ ๋ถ€๋ชจ ๊ธฐ๋ณธ ๋™์ž‘์„ ํ™•์žฅํ•ด์„œ ์“ฐ๋Š” ๊ฒฝ์šฐ๋Š” ์ƒ์†์ด ์ ํ•ฉ


โœ… 4. ์–ธ์ œ Composition์„ ์จ์•ผ ํ• ๊นŒ?

โœ… ์˜ˆ1: ๊ธฐ๋Šฅ ์กฐํ•ฉ์ด ๋ชฉ์ ์ผ ๋•Œ


  
class NotificationSender {
void send(String msg) {
System.out.println("Sending: " + msg);
}
}
class OrderService {
NotificationSender sender = new NotificationSender();
void completeOrder() {
sender.send("Order completed!");
}
}

โžก๏ธ OrderService is-a Sender๋Š” ์•„๋‹˜ โ†’ ๊ธฐ๋Šฅ๋งŒ ํฌํ•จํ•ด์„œ ์‚ฌ์šฉ


โœ… ์˜ˆ2: ๋™์ž‘์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ต์ฒดํ•ด์•ผ ํ•  ๋•Œ (์ „๋žต ํŒจํ„ด)


  
interface PayStrategy {
void pay(int amount);
}
class KakaoPay implements PayStrategy {
public void pay(int amount) {
System.out.println("Paid with KakaoPay");
}
}
class PaymentProcessor {
PayStrategy strategy;
PaymentProcessor(PayStrategy strategy) {
this.strategy = strategy;
}
void process(int amount) {
strategy.pay(amount);
}
}

โžก๏ธ ๋Ÿฐํƒ€์ž„์— ์ „๋žต(๊ฒฐ์ œ ์ˆ˜๋‹จ) ๊ต์ฒด ๊ฐ€๋Šฅ โ†’ ๊ตฌ์„ฑ ๋ฐฉ์‹์˜ ๋Œ€ํ‘œ์  ์žฅ์ 

๋”๋ณด๊ธฐ

โœ… ์ „๋žต ํŒจํ„ด์„ ํ†ตํ•ด ๊ตฌ์„ฑ(Composition)์œผ๋กœ ๋™์ž‘์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ต์ฒดํ•˜๋Š” ๋ฐฉ์‹

 

๐Ÿ“Œ ๊ฐœ๋… ์„ค๋ช…

๋•Œ๋•Œ๋กœ ์šฐ๋ฆฌ๋Š” ๊ฐ™์€ ๋™์ž‘์„ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

  • ์˜ค๋Š˜์€ ์นด์นด์˜คํŽ˜์ด๋กœ ๊ฒฐ์ œ
  • ๋‚ด์ผ์€ ์‹ ์šฉ์นด๋“œ๋กœ ๊ฒฐ์ œ
  • ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐ€์งœ ๊ฒฐ์ œ๋กœ ์ฒ˜๋ฆฌ

์ด๋•Œ ์ƒ์†์œผ๋กœ๋Š” ๋™์ž‘ ๊ต์ฒด๊ฐ€ ์–ด๋ ต๊ณ ,
์ธํ„ฐํŽ˜์ด์Šค + ๊ตฌ์„ฑ(Composition) ์„ ํ™œ์šฉํ•˜๋ฉด ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โžก๏ธ ์ด ๋ฐฉ์‹์ด ์ „๋žต ํŒจํ„ด (Strategy Pattern) ์ž…๋‹ˆ๋‹ค.


๐ŸŽฏ ์ „๋žต ํŒจํ„ด ๊ฐœ๋… ์š”์•ฝ


์š”์†Œ  ์—ญํ• 
์ธํ„ฐํŽ˜์ด์Šค ๊ณตํ†ต ๋™์ž‘์˜ "๊ณ„์•ฝ" ์ •์˜ (ex. pay)
๊ตฌํ˜„ ํด๋ž˜์Šค ๊ฐ๊ฐ์˜ ์ „๋žต์„ ์‹ค์ œ๋กœ ๊ตฌํ˜„ (ex. KakaoPay, CardPay)
Context ํด๋ž˜์Šค ๋™์ž‘์„ ์‹คํ–‰ํ•˜์ง€๋งŒ ์ „๋žต์€ "๋ฐ”๊นฅ์—์„œ ์ฃผ์ž…"๋ฐ›์Œ

โœ… ์˜ˆ์ œ ์ฝ”๋“œ

 

1) ๊ณตํ†ต ๋™์ž‘ ์ •์˜ (์ธํ„ฐํŽ˜์ด์Šค)


  
interface PayStrategy {
void pay(int amount);
}

 

2) ์ „๋žต ๊ตฌํ˜„์ฒด (์—ฌ๋Ÿฌ ๊ฐœ)


  
class KakaoPay implements PayStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " with KakaoPay");
}
}
class CardPay implements PayStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " with Credit Card");
}
}

 

3) ์‹คํ–‰ ํด๋ž˜์Šค (์ „๋žต์„ ๋ฐ›์•„์„œ ์œ„์ž„)


  
class PaymentProcessor {
private PayStrategy strategy;
public PaymentProcessor(PayStrategy strategy) {
this.strategy = strategy;
}
public void process(int amount) {
strategy.pay(amount); // ์ „๋žต์—๊ฒŒ ์‹คํ–‰ ์œ„์ž„
}
}

๐Ÿงช ์‚ฌ์šฉ ์˜ˆ์‹œ


  
PayStrategy strategy = new KakaoPay(); // ์ „๋žต ์„ ํƒ
PaymentProcessor processor = new PaymentProcessor(strategy);
processor.process(10000); // ์ถœ๋ ฅ: Paid 10000 with KakaoPay
// ์ „๋žต ๊ต์ฒด
processor = new PaymentProcessor(new CardPay());
processor.process(10000); // ์ถœ๋ ฅ: Paid 10000 with Credit Card

๐Ÿ’ก ์ด ๊ตฌ์กฐ์˜ ์žฅ์ 


์žฅ์  ์„ค๋ช…
์œ ์—ฐ์„ฑ ์‹คํ–‰ ์ค‘ ์ „๋žต(๋™์ž‘)์„ ์‰ฝ๊ฒŒ ๊ต์ฒด ๊ฐ€๋Šฅ
ํ…Œ์ŠคํŠธ ์šฉ์ด ๋ชจ์˜ ์ „๋žต(MockStrategy)์œผ๋กœ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ
์žฌ์‚ฌ์šฉ์„ฑ ์ „๋žต ๊ตฌํ˜„์ฒด๋“ค์„ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ํ™œ์šฉ ๊ฐ€๋Šฅ
๊ฒฐํ•ฉ๋„ ๋‚ฎ์Œ ์‹คํ–‰ ํด๋ž˜์Šค๋Š” PayStrategy์—๋งŒ ์˜์กดํ•˜๊ณ , ๊ตฌ์ฒด ๊ตฌํ˜„์ฒด๋Š” ๋ชฐ๋ผ๋„ ๋จ

๐Ÿ“Œ ์ •๋ฆฌ: ์ „๋žต ํŒจํ„ด์ด ํ•„์š”ํ•œ ์ƒํ™ฉ

  • ํŠน์ • ๊ธฐ๋Šฅ(์˜ˆ: ๊ฒฐ์ œ, ์ •๋ ฌ, ์ถœ๋ ฅ)์„ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๋•Œ
  • ์‹คํ–‰ ์ค‘์— ์ „๋žต์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ
  • ํ…Œ์ŠคํŠธ ์‹œ ์‹ค์ œ ์ „๋žต ๋Œ€์‹  ๊ฐ€์งœ(Mock)๋ฅผ ์“ฐ๊ณ  ์‹ถ์„ ๋•Œ
  • ์ƒ์†๋ณด๋‹ค ๋” ์œ ์—ฐํ•œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ

โœ… ๊ฒฐ๋ก  ์š”์•ฝ

ํ•ญ๋ชฉ  ์ƒ์† (Inheritance)  ๊ตฌ์„ฑ (Composition)
๊ตฌ์กฐ ๊ณ„์ธต์  (is-a) ์กฐํ•ฉ์  (has-a, uses-a)
๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ๊ฐ•๊ฑดํ•จ ์•ฝํ•จ (๋ถ€๋ชจ ๋ณ€๊ฒฝ โ†’ ์ž์‹ ์˜ํ–ฅ) ๊ฐ•ํ•จ (๋‚ด๋ถ€ ๊ตฌ์„ฑ๋งŒ ๊ต์ฒด)
๋™์ž‘ ํ™•์žฅ ์ƒ์† or ์˜ค๋ฒ„๋ผ์ด๋”ฉ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ์ „๋žต ๊ต์ฒด
์œ ์—ฐ์„ฑ ๋‚ฎ์Œ โœ… ๋†’์Œ
ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ ์–ด๋ ค์›€ โœ… ๋†’์Œ

 


โœ… ์˜ˆ3: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ


  
class ReportGenerator {
FileWriter writer;
ReportGenerator(FileWriter writer) {
this.writer = writer;
}
void generate() {
writer.write("Report...");
}
}

โžก๏ธ ์‹ค์ œ ์‹คํ–‰์—์„œ๋Š” FileWriter, ํ…Œ์ŠคํŠธ์—์„œ๋Š” MockWriter ์‚ฌ์šฉ ๊ฐ€๋Šฅ


๐ŸŽฏ ๊ฒฐ๋ก  ์š”์•ฝ: ์–ธ์ œ ์–ด๋–ค ๊ฑธ ์จ์•ผ ํ•˜๋‚˜?

์ƒํ™ฉ ์ƒ์† (Inheritance) ๊ตฌ์„ฑ (Composition)
์ง„์งœ๋กœ is-a ๊ด€๊ณ„์ผ ๋•Œ โœ… ์‚ฌ์šฉ โŒ ๋ถˆํ•„์š”
๊ธฐ๋Šฅ ์žฌ์‚ฌ์šฉ์ด ๋ชฉ์ ์ผ ๋•Œ โŒ ์œ„ํ—˜ โœ… ์œ ๋ฆฌ
์œ ์—ฐํ•˜๊ฒŒ ๊ต์ฒด ๊ฐ€๋Šฅํ•ด์•ผ ํ•  ๋•Œ โŒ ๋ถˆํŽธ โœ… ๊ฐ€๋Šฅ
ํ…Œ์ŠคํŠธ, ํ™•์žฅ ๊ณ ๋ ค ์‹œ โŒ ๋‹จ์  ๋งŽ์Œ โœ… ์žฅ์  ๋งŽ์Œ
๊ด€๊ณ„๊ฐ€ has-a / uses-a โŒ ๋ถ€์ ์ ˆ โœ… ์ ์ ˆ
๋Œ€ํ‘œ ์ ์šฉ ํŒจํ„ด ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด ์ „๋žต ํŒจํ„ด, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ, DI

๐Ÿง  ํ•ต์‹ฌ ์ฒ ํ•™

โœ… "๊ฐ€๋Šฅํ•œ ํ•œ ์ƒ์†๋ณด๋‹ค ๊ตฌ์„ฑ์„ ์„ ํ˜ธํ•˜๋ผ (Favor composition over inheritance)"
โ€” Effective Java, Joshua Bloch


๋Œ“๊ธ€