깊은 상속의 한계
Coddy JavaScript 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 56개 중 48번째.
상속은 유용하지만, 매우 깊은 상속 계층 구조(부모 → 자식 → 손자 → 증손자)를 만드는 것은 문제를 일으킬 수 있습니다. 계층 구조가 깊어질수록 코드를 이해하고 유지 관리하며 수정하는 것이 더 어려워집니다.
깊은 상속 체인에서 어떤 일이 일어나는지 살펴봅시다:
// Base class
class Vehicle {
constructor(type) {
this.type = type;
this.isRunning = false;
}
start() {
this.isRunning = true;
console.log(`${this.type} started`);
}
}
// First level of inheritance
class Car extends Vehicle {
constructor(make, model) {
super("Car");
this.make = make;
this.model = model;
this.wheels = 4;
}
honk() {
console.log("Beep beep!");
}
}
// Second level of inheritance
class SportsCar extends Car {
constructor(make, model, topSpeed) {
super(make, model);
this.topSpeed = topSpeed;
}
race() {
this.start();
console.log(`Racing at ${this.topSpeed} mph!`);
}
}이 예제에서 SportsCar는 상속 구조에서 2단계 깊이에 있습니다. 이는 몇 가지 문제로 이어질 수 있습니다:
- Vehicle에 대한 변경 사항이 예기치 않게 SportsCar를 망가뜨릴 수 있습니다
- 상속 체인이 길어질수록 메서드와 속성이 어디에서 오는지 추적하기가 더 어려워집니다
- 충분히 유연하지 않을 수 있는 "is-a" 관계를 강요받게 됩니다
챌린지
로봇이 작동할 수 있도록 Robot.js 파일을 완성하세요. 현재 로봇은 조립되었지만 아무것도 할 수 없는 상태입니다.
Robot.js에서 해야 할 일:
- Robot 생성자 내부에서 speaker와 mover 컴포넌트를 생성하세요.
- 메서드에서 컴포넌트를 사용하세요:
greet()에서:this.speaker.speak("Hello!");를 호출하세요.walkForward()에서:this.mover.move("forward");를 호출하세요.
이렇게 하는 이유: 이것은 합성(composition)입니다. 로봇은 더 작은 컴포넌트들을 결합하여 만들어집니다. 로봇은 이러한 능력을 상속받는 대신, 말하기 위한 speaker를 가지고 있고(has-a), 움직이기 위한 mover를 가지고 있습니다(has-a).
치트 시트
깊은 상속 계층 구조(부모 → 자식 → 손자)는 유지보수 문제와 유연성 부족을 초래할 수 있습니다. 체인이 깊어질수록 코드를 이해하고 수정하는 것이 더 어려워집니다.
깊은 상속 체인의 예시:
class Vehicle {
constructor(type) {
this.type = type;
this.isRunning = false;
}
start() {
this.isRunning = true;
console.log(`${this.type} started`);
}
}
class Car extends Vehicle {
constructor(make, model) {
super("Car");
this.make = make;
this.model = model;
}
}
class SportsCar extends Car {
constructor(make, model, topSpeed) {
super(make, model);
this.topSpeed = topSpeed;
}
}깊은 상속의 문제점:
- 기본 클래스(base classes)의 변경이 예기치 않게 자식 클래스를 망가뜨릴 수 있음
- 메서드와 속성이 어디에서 기원했는지 추적하기 어려움
- 유연성이 부족한 엄격한 "is-a" 관계를 강제함
대안으로서의 구성(Composition): 상속 대신, 객체가 컴포넌트와 have-a 관계를 갖는 구성을 사용하여, 작은 부분들을 결합해 기능을 구축하십시오.
직접 해보기
import { Robot } from './Robot.js';
const myRobot = new Robot('Robo');
myRobot.greet(); // 출력 결과: Saying: "Hello!"
myRobot.walkForward(); // 출력 결과: Moving forward이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.