상속(Inheritance), 구성(Composition), 그리고 인터페이스
상속 (Inheritance)
-
정의: 한 클래스(자식 클래스)가 다른 클래스(부모 클래스)의 속성과 메서드를 상속받는 것.
-
특징
- 코드 재사용: 부모 클래스의 기능을 자식 클래스가 재사용할 수 있어 코드 중복을 줄일 수 있습니다.
- 계층적 분류: 클래스 간에 계층 구조를 형성하여, 보다 명확한 구조를 가진 코드를 작성할 수 있습니다.
- 강한 결합: 부모 클래스에 대한 의존성이 강해, 부모 클래스의 변경이 자식 클래스에 영향을 줄 수 있습니다.
- 확장성 제한: 자바는 단일 상속만을 지원하기 때문에, 여러 클래스로부터 상속받을 수 없습니다.
-
예시
// 부모 클래스
class Vehicle {
public void move() {
System.out.println("Vehicle is moving");
}
}
// 자식 클래스
class Car extends Vehicle {
@Override
public void move() {
System.out.println("Car is moving");
}
}
public class Test {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.move(); // 출력: "Car is moving"
}
}
구성 (Composition)
- 정의: 한 클래스가 다른 클래스의 인스턴스를 포함하여 해당 클래스의 기능을 사용하는 것.
-
특징
- 유연성: 구성은 클래스 간 느슨한 결합을 형성하여, 변경이 용이하고 확장성이 높습니다.
- 독립적인 생명주기: 구성하는 객체는 포함하는 객체의 생명주기와 독립적일 수 있습니다.
- 재사용성: 여러 클래스에서 동일한 객체를 재사용할 수 있어, 코드 중복을 효과적으로 줄일 수 있습니다.
- 상속의 대안: 상속의 단점을 보완하는 방법으로 사용될 수 있습니다.
- 예시
class Engine {
void start() {
// 엔진을 시작하는 로직
}
}
class Car {
private Engine engine; // 구성 관계
Car() {
this.engine = new Engine(); // 엔진 객체를 생성하여 구성
}
void startCar() {
engine.start(); // 구성된 엔진 객체를 사용하여 자동차를 시작
}
}
인터페이스를 통한 구현
-
정의: 클래스가 인터페이스의 모든 추상 메서드를 구현함으로써 인터페이스의 계약을 충족시키는 것.
-
특징
- 계약 기반 프로그래밍: 인터페이스는 구현해야 할 메서드의 시그니처를 제공하여, 특정 기능을 강제합니다.
- 다형성 촉진: 서로 다른 클래스들이 동일한 인터페이스를 구현함으로써, 다형적인 방식으로 객체들을 다룰 수 있습니다.
- 느슨한 결합: 인터페이스를 통해 클래스 간의 의존성을 최소화하고, 변경에 유연하게 대응할 수 있습니다.
- 다중 구현 가능: 자바에서 클래스는 여러 인터페이스를 구현할 수 있어, 단일 상속의 제한을 극복할 수 있습니다.
종합 비교
- 사용 시나리오:
- 상속: “is-a” 관계가 명확할 때 사용하며, 강한 클래스 계층이 필요한 경우에 적합합니다.
- 구성: “has-a” 관계를 표현하며, 더 유연하고 독립적인 관계 설정이 필요할 때 사용합니다.
- 인터페이스: 다양한 클래스가 동일한 기능을 제공해야 하지만 구현 방식이 다를 때 사용합니다.
- 선택 기준:
- 상속은 클래스 간 강한 관계가 필요할 때 적합하지만, 오버유즈는 피해야 합니다.
- 구성은 유연성과 재사용성을 중시할 때 좋은 선택입니다.
- 인터페이스는 다형성과 느슨한 결합을 중시할 때 적합합니다.
참고
- ChatGPT-4.0
보완/복습
- 2023.11.23 생성