티스토리 뷰
목차
1. 상속이란?
상속(Inheritance)은 기존 클래스의 속성과 동작(메서드)을 자식 클래스가 물려받아 사용하는 객체지향의 핵심 기능이다.
- 즉, 부모 클래스의 기능을 확장하거나 재사용하기 위해 자식 클래스가 상속을 받는 것이다.
public class Animal {
public void sound() {
Systme.out.println("동물이 소리를 냅니다.");
}
}
public class Dog extends Animal {
@Override
public void sound() {
System.out.println("멍멍!");
}
}
2. 상속의 목적
| 목적 | 설명 |
| 코드 재사용 | 중복 제거, 공통 로직 분리 |
| 계층적 관계 표현 | 일반 -> 구체 구조 표현(is-a 관계) |
| 확장성 확보 | 부모 기능을 재정의하여 기능 확장(Overriding) |
3. 상속의 기본 구조 (Java 기준)
📌 extends 키워드
class 자식 extends 부모 {
// 부모의 필드/메서드 사용 가능
}
📌 메서드 오버라이딩 (재정의)
@Override
public void methodName() {
// 부모 메서드 재정의
}
📌 super 키워드
- 부모의 생성자나 메서드/필드에 접근할 때 사용
super.method(); // 부모 메서드 호출
super.field = value; // 부모 필드 접근
4. 상속이 가진 단점
- 상속은 강력하지만 다음과 같은 설계상 문제를 유발할 수 있다.
❌ 강한 결합 (Tight Coupling)
- 자식 클래스가 부모 클래스에 너무 의존하게 됨
- 부모 변경 -> 자식에 ripple effect
❌ is-a 관계 오용
- 상속 = 코드 재사용으로만 생각해 불필요하게 계층만 복잡해짐
- 진짜 "is-a" 관계가 아닐 수도 있음 (예 : Car extends Engine ❌)
❌ 테스트 어려움
- 상속 깊어질수록 테스트 단위가 복잡해짐
❌ 다중 상속 불가 (Java 기준)
- Java는 클래스 간 다중 상속을 금지 -> 인터페이스로 해결 필요
Java가 다중 상속을 지원하지 않는 이유는 대표적으로 "다이아몬드 문제(Diamond Problem)" 때문이다.
두 부모 클래스에서 동일한 메서드를 상속받을 경우 어떤 메서드를 호출해야 할지 모호성이 발생하고, 이는 객체의 일관성을 깨뜨리고 캡슐화의 원칙을 위반할 수 있다.
그래서 Java는 클래스 간 다중 상속은 금지하고, 인터페이스를 통한 다중 구현으로 유연성을 확보하면서도 안정성을 유지할 수 있다.
5. 실무에서 자주 보는 잘못된 상속 설계 예시
public class Employee {
private String name;
private int salary;
public void printPaySlip() {
// 급여 출력
}
}
public class Manager extends Employee {
private List<Employee> team;
public void evaluate(Employee e) { ... }
}
▶ Manager is-a Employee는 맞지만, 나중에 Manage 외에 HR, TechLead, PM 등 공통점보다 차이점이 많아지고 설계가 깨지기 시작함
6. 상속의 대안 -> 합성 (Composition)
📌
상속 vs 합성 비교
| 구분 | 상속 (Inheritance) | 합성 (Composition) |
| 관계 | is-a (이다) | has-a (가지고 있다) |
| 결합도 | 높음 | 낮음 (유연함) |
| 재사용 방식 | 부모의 모든 기능 물려받음 | 필요한 기능만 포함 |
| 설계 유연성 | 제한적 | 확장성 높음 |
✅ 합성 예시
public class Logger{
public void log(String msg) {
System.out.println("[LOG] " + msg);
}
}
public class Service {
private Logger logger;
public Service(Logger logger) {
this.logger = logger;
}
public void doSomething() {
logger.log("서비스 수행 중...");
}
}
- "Service는 Logger가 아니다" -> 상속 부적합
- "Service는 Logger를 가지고 있다" -> 합성이 맞음
✅ 마무리 요약
- 상속은 객체지향의 핵심 개념이지만 과용하면 설계가 무너지기 쉽다.
- 자식 클래스는 부모 클래스의 강하게 결합되며, 변경에 취약해 질 수 있다.
- 단순한 코드 재사용 목적이라면 합성(Composition)이 더 적합할 수 있다.
🔜 다음 포스팅에서는 "다형성 - 한 가지 인터페이스, 여러 가지 구현" 라는 주제를 다뤄보려고 한다.
'IT > OOP' 카테고리의 다른 글
| 추상화(Abstraction) - 복잡함을 감추고 본질만 드러내는 설계의 미학 (0) | 2025.04.16 |
|---|---|
| 🌀다형성(Polymorphism) - 한 인터페이스, 여러 구현의 힘 (0) | 2025.04.15 |
| 🔒 캡슐화(Encapsulation) - 객체지향의 시작점, 복잡성의 종착역 (0) | 2025.04.14 |
| 객체지향 프로그래밍(OOP) (0) | 2025.03.11 |