개발 상식/객체 지향 & 설계
[객체 지향] 코드를 재사용 하기위한 상속과 조합
kku_lurgi
2024. 2. 23. 18:36
우아한 테크코스 2주차 입니다.
이번 미션에서는 조합과 상속에 대해서 공부했습니다!
❗중복 코드 발생
class Lotto {
constructor(numbers) {
if (numbers.some((number) => number > MAX_NUMBER || number < MIN_NUMBER)) {
throw new Error("로또 번호는 1~45 사이의 정수여야 합니다.");
}
if (numbers.length !== 6) {
throw new Error("로또 번호는 6개여야 합니다.");
}
if (numbers.length !== new Set(numbers).size) {
throw new Error("로또 번호는 중복되지 않아야 합니다.");
}
this.#numbers = numbers;
}
}
class WinningLotto {
constructor(numbers, bonusNumber) {
if (numbers.some((number) => number > MAX_NUMBER || number < MIN_NUMBER)) {
throw new Error("로또 번호는 1~45 사이의 정수여야 합니다.");
}
if (numbers.length !== 6) {
throw new Error("로또 번호는 6개여야 합니다.");
}
if (numbers.length !== new Set(numbers).size) {
throw new Error("로또 번호는 중복되지 않아야 합니다.");
}
if (numbers.includes(bonusNumber)) {
throw new Error("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
this.numbers = numbers;
this.bonusNumber = bonusNumber;
}
}
Lotto 클래스와 WinLotto 클래스에서 중복이 되는 부분을 상속을 통해 해결할 수 있습니다.
❓상속과 조합의 차이
상속
class WinningLotto extends Lotto {
constructor(numbers, bonusNumber) {
super(numbers);
if (numbers.includes(bonusNumber)) {
throw new Error("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
this.bonusNumber = bonusNumber;
}
}
new WinningLotto([1,2,3,4,5,6], 7);
extends 키워드를 이용한 강한 결합을 통해 클래스를 생성하였습니다.
조합
class WinningLotto {
constructor(winningLotto, bonusNumber) {
if (winningLotto.has(bonusNumber)) {
throw new Error("보너스 번호는 당첨 번호와 중복될 수 없습니다.");
}
this.winningLotto = winningLotto;
this.bonusNumber = bonusNumber;
}
}
new WinningLotto(new Lotto([1,2,3,4,5,6]), 7);
매개변수로 받은 객체로 느슨한 결합을 통해 클래스를 생성하였습니다.
❓이렇게 하면 안될까?
- 동적 언어인 JS에서는 Java에서의 List<Integer> lottoNumbers 와 int[] lottoNumbers차이가 없다. 즉 정적 언어인 Java에서는 캡슐화가 깨지겠지만, JS에서는 큰 변화가 없다.
- 따라서 위 블로그 글에서의 예제를 살펴 보았을 때, 자식 요소의 코드를 수정하는 비용과 부모 코드를 수정하는 비용이 크게 다르지 않을 것이다.
❗’오브젝트: 코드로 이해하는 객체지향 설계’에서 말하는 상속의 문제점
- 상속을 염두에 두고 설계되지 않은 클래스를 상속을 이용해 자숑하는 것은 생각처럼 쉽지않다.
- 재사용을 위해 상속 계층 사이에 무수히 많은 가정을 세웠을지 모른다.
- 취약한 기반 클래스 문제 (Fragile Base Class Problem, Brittle Base Class Problem). 이는 부모 클래스의 변경이 자식 클래스에 영향을 미치는 것을 의미합니다.
- 불필요한 인터페이스 상속 문제. 이는 상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨뜨릴 수 있다는 것입니다.
- 부모 클래스와 자식 클래스의 동시 수정 문제. 클래스 상속은 자식 클래스가 변경될 때 부모 클래스를 함께 변경하거나, 둘 다 영원히 변경하지 않아야 한다는 것이다.
- 메서드의 오버라이딩의 오작용 문제. 자식 클래스가 부모 클래스의 메서드를 오버라이딩 할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.
✨나의 생각.
위 문제 모두 JS에서의 상속의 문제를 보여준다고 생각하지는 않습니다. 그저 추상화 단계에서의 설계에서 관점의 차이라고 생각이 들어요.
의존성 주입이 필요한 has-a 관계라면 조합을 사용하고, 이번 로또 미션과 같은 is-a 관계에서는 상속을 충분히 사용해도 괜찮다고 생각합니다!