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)을 선택하는 것이 좋은 설계 원칙입니다. 실무에서는 유연성과 유지보수성 때문에 상속보다 구성을 우선적으로 고려하는 경우가 많습니다.