개발 상식/객체 지향 & 설계

[객체 지향] 코드를 재사용 하기위한 상속과 조합

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);

매개변수로 받은 객체로 느슨한 결합을 통해 클래스를 생성하였습니다.

 

상속보다는 조합(Composition)을 사용하자.

tecoble.techcourse.co.kr

 

❓이렇게 하면 안될까?

  1. 동적 언어인 JS에서는 Java에서의 List<Integer> lottoNumbers 와 int[] lottoNumbers차이가 없다. 즉 정적 언어인 Java에서는 캡슐화가 깨지겠지만, JS에서는 큰 변화가 없다.
  2. 따라서 위 블로그 글에서의 예제를 살펴 보았을 때, 자식 요소의 코드를 수정하는 비용과 부모 코드를 수정하는 비용이 크게 다르지 않을 것이다.

❗’오브젝트: 코드로 이해하는 객체지향 설계’에서 말하는 상속의 문제점

  1. 상속을 염두에 두고 설계되지 않은 클래스를 상속을 이용해 자숑하는 것은 생각처럼 쉽지않다.
  2. 재사용을 위해 상속 계층 사이에 무수히 많은 가정을 세웠을지 모른다.
  3. 취약한 기반 클래스 문제 (Fragile Base Class Problem, Brittle Base Class Problem). 이는 부모 클래스의 변경이 자식 클래스에 영향을 미치는 것을 의미합니다.
  4. 불필요한 인터페이스 상속 문제. 이는 상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨뜨릴 수 있다는 것입니다.
  5. 부모 클래스와 자식 클래스의 동시 수정 문제. 클래스 상속은 자식 클래스가 변경될 때 부모 클래스를 함께 변경하거나, 둘 다 영원히 변경하지 않아야 한다는 것이다.
  6. 메서드의 오버라이딩의 오작용 문제. 자식 클래스가 부모 클래스의 메서드를 오버라이딩 할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.

 

✨나의 생각.

위 문제 모두 JS에서의 상속의 문제를 보여준다고 생각하지는 않습니다. 그저 추상화 단계에서의 설계에서 관점의 차이라고 생각이 들어요.

의존성 주입이 필요한 has-a 관계라면 조합을 사용하고, 이번 로또 미션과 같은 is-a 관계에서는 상속을 충분히 사용해도 괜찮다고 생각합니다!