어제 오늘 내일

[Java] 합성(Composition) vs 상속(Inheritance) 본문

IT/Java

[Java] 합성(Composition) vs 상속(Inheritance)

hi.anna 2025. 12. 28. 00:20

Java에서 객체지향 설계를 할 때 중요한 선택 중 하나는
“상속(Inheritance)을 사용할 것인가, 합성(Composition)을 사용할 것인가?” 입니다.
두 개념은 모두 객체 간 관계를 표현하지만, 구조적 차이와 설계 철학에서 큰 차이를 보입니다.

이 글에서는 합성과 상속의 개념, 특징, 차이점, 언제 사용해야 하는지 명확하게 정리합니다.

 

1. 상속(Inheritance)

상속은 부모 클래스의 기능을 자식 클래스가 물려받는 관계입니다.
is-a 관계라고도 부릅니다.

예:

class Animal {
    void eat() {
        System.out.println("먹습니다");
    }
}

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

Dog is-a Animal 관계

  • Dog는 Animal이다
  • Animal의 기능(eat)을 자동으로 상속받음

상속의 장점

  • 코드 재사용 쉬움
  • 다형성 활용 가능
  • 계층 구조를 만들기 좋음

상속의 단점

  • 부모와 자식의 결합도가 매우 높아짐
  • 부모의 변경이 자식에 큰 영향을 줌
  • 잘못 사용하면 복잡하고 경직된 구조가 될 수 있음

 

2. 합성(Composition)

합성은 다른 객체를 자신의 필드로 포함해 기능을 사용하는 방식입니다.
has-a 관계라고 부릅니다.

예:

class Engine {
    void start() {
        System.out.println("엔진 시동!");
    }
}

class Car {
    private Engine engine = new Engine(); // 합성

    void drive() {
        engine.start();
        System.out.println("차가 움직입니다!");
    }
}

Car has-a Engine 관계

  • Car는 Engine을 “가지고 있다”
  • Engine 기능을 Car 내부에서 사용

합성의 장점

  • 객체 간 결합도가 낮음 (유연한 구조)
  • 변경에 강함 (부품만 교체 가능)
  • 코드 재사용은 유지하면서 상속의 단점 감소
  • 인터페이스를 조합하여 더 유연한 설계 가능

합성의 단점

  • 코드가 약간 길어질 수 있음
  • 관계가 명확한 경우 상속보다 덜 직관적일 수 있음

 

3. 합성 vs 상속 비교

구분 합성(Composition) 상속(Inheritance)
결합도 낮음 (Loosely Coupled) 높음 (Tightly Coupled)
유연성 높음 낮음
재사용성 높음 높음
구현 방식 필드에 객체 포함 extends로 상속
유지보수성 좋음 부모 변화에 민감
다형성 인터페이스 기반으로 가능 자동 지원

핵심 요약

  • 상속: 구조가 명확하고, 계층적 설계가 필요할 때
  • 합성: 유연함이 중요하고, 변경에 강한 구조를 만들고 싶을 때

 

4. 상속 대신 합성을 사용해야 하는 경우

다음 상황이라면 상속보다 합성이 훨씬 추천됩니다.

✔ “부모 클래스를 수정하면 자식이 다 깨질 것 같을 때”

상속은 부모가 바뀌면 자식도 영향받습니다.

✔ “클래스 간 관계가 진짜 is-a인지 확신할 수 없을 때”

억지로 상속하면 구조가 꼬임.

✔ “여러 기능을 조합해서 사용해야 할 때”

상속은 하나만 가능하지만, 합성은 여러 객체 조합 가능.

✔ “유지보수가 쉬운 구조를 만들고 싶을 때”

합성은 객체 조합만 바꾸면 기능을 변경할 수 있음.

 

5. 합성과 상속을 함께 보자: 예시 비교

상속 사용:

class Printer {
    void print() {
        System.out.println("출력!");
    }
}

class SmartPrinter extends Printer {
    void connectWifi() {
        System.out.println("WiFi 연결!");
    }
}

합성 사용:

class Printer {
    void print() {
        System.out.println("출력!");
    }
}

class SmartDevice {
    private Printer printer = new Printer();

    void print() {
        printer.print();
    }

    void connectWifi() {
        System.out.println("WiFi 연결!");
    }
}

설명

  • SmartPrinter is-a Printer → 상속
  • SmartDevice has-a Printer → 합성

두 방식 모두 "프린트 기능"을 재사용하지만 구조적 유연성은 합성이 더 높음.

 

6. 언제 상속을 선택해야 할까?

상속은 아래 상황에 적합합니다.

  • 명확한 is-a 관계일 때
    (예: 고양이는 동물이다)
  • 부모의 기능을 확장하는 것이 목적일 때
  • 다형성을 적극 활용해야 할 때

 

7. 정리

  • 상속(Inheritance): is-a 관계, 코드 재사용은 쉽지만 결합도가 높음
  • 합성(Composition): has-a 관계, 유연하고 유지보수가 쉽고 결합도가 낮음
  • 설계 시 “정말 is-a 관계인가?”를 먼저 판단
  • 일반적으로 합성이 상속보다 더 권장되는 현대적 설계 방식

 

 

반응형
Comments