Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java의 IS-A(상속) vs HAS-A(구성) 관계 완벽 정리

IS-A 관계란?

IS-A 관계는 "이 객체는 저 객체의 한 종류(type)다"라고 표현하는 방식입니다. Java에서는 extends 키워드를 사용하여 상속을 통해 IS-A 관계를 구현합니다.

public class Animal {
}
public class Mammal extends Animal {
}
public class Reptile extends Animal {
}
public class Dog extends Mammal {
}

위 코드를 IS-A 관계로 해석하면 다음과 같습니다.

  • Mammal은 Animal이다 (Mammal IS-A Animal)
  • Reptile은 Animal이다 (Reptile IS-A Animal)
  • Dog는 Mammal이다 (Dog IS-A Mammal)
  • 따라서 Dog는 Animal이기도 하다 (Dog IS-A Animal)

extends 키워드를 사용하면 하위 클래스(서브클래스)는 상위 클래스(슈퍼클래스)의 private 멤버를 제외한 모든 속성과 메서드를 상속받을 수 있습니다.

또한 instanceof 연산자를 사용하면 특정 객체가 실제로 해당 타입에 속하는지 확인할 수 있습니다.

예제 코드

class Animal {
} 
class Mammal extends Animal {
} 
class Reptile extends Animal {
} 
public class Dog extends Mammal {
    public static void main(String args[]) {
        Animal a = new Animal();
        Mammal m = new Mammal();
        Dog d = new Dog();
        System.out.println(m instanceof Animal);
        System.out.println(d instanceof Mammal);
        System.out.println(d instanceof Animal);
    }
}

실행 결과

true
true
true

Mammal 객체는 Animal의 인스턴스이고, Dog 객체는 Mammal이자 Animal의 인스턴스임을 확인할 수 있습니다. 이것이 바로 상속 계층 구조에서 IS-A 관계가 성립하는 방식입니다.

HAS-A 관계란?

HAS-A 관계는 주로 기능의 사용 여부를 기준으로 성립합니다. 즉, 어떤 클래스가 특정 객체를 멤버 변수로 가지고 있는지를 나타내며, 이를 흔히 구성(composition)이라고 부릅니다. HAS-A 관계를 활용하면 코드 중복을 줄이고 버그 발생 가능성도 낮출 수 있습니다.

예제 코드

public class Vehicle{ }
public class Speed{ }
public class Van extends Vehicle {
    private Speed sp;   
}

위 코드는 "Van 클래스는 Speed를 가진다(Van HAS-A Speed)"는 관계를 보여줍니다. Speed를 별도의 클래스로 분리했기 때문에 Speed와 관련된 모든 코드를 Van 클래스 내부에 작성할 필요가 없습니다. 덕분에 Speed 클래스는 여러 애플리케이션에서 자유롭게 재사용할 수 있습니다.

캡슐화와 구현 은닉

객체지향 프로그래밍에서 사용자는 실제로 어떤 객체가 작업을 수행하는지 알 필요가 없습니다. Van 클래스는 내부 구현 세부 사항을 외부로부터 숨기고, 사용자가 특정 동작을 요청하면 Van 클래스가 직접 처리하거나 다른 클래스(예: Speed)에 작업을 위임합니다. 이러한 방식이 바로 HAS-A 관계가 제공하는 핵심 이점입니다.

IS-A vs HAS-A, 언제 무엇을 사용해야 할까?

구분IS-A (상속)HAS-A (구성)
관계의 의미~은 ~의 한 종류이다~은 ~을 가지고 있다
구현 방식extends 키워드멤버 변수로 객체 참조
결합도높음 (강한 결합)낮음 (느슨한 결합)
적합한 경우명확한 계층 구조가 있을 때 (Dog → Mammal → Animal)기능을 재사용하거나 유연하게 교체해야 할 때

일반적으로 "~은 ~의 일종이다"라는 문장이 자연스럽게 성립하면 상속(IS-A)을, 그렇지 않고 단순히 기능을 빌려 쓰는 관계라면 구성(HAS-A)을 선택하는 것이 좋은 설계 원칙입니다. 실무에서는 유연성과 유지보수성 때문에 상속보다 구성을 우선적으로 고려하는 경우가 많습니다.