Menu
Coddy logo textTech

深い継承の限界

CoddyのJavaScriptジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 48/56。

継承は便利ですが、非常に深い継承階層(親 → 子 → 孫 → ひ孫)を作成することは、問題を引き起こす可能性があります。階層が深くなればなるほど、コードの理解、保守、および修正が困難になります。

深い継承チェーンで何が起こるか見てみましょう:

// 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レベルの深さにあります。これにより、いくつかの問題が発生する可能性があります:

  1. Vehicle への変更が予期せず SportsCar を壊す可能性があります
  1. 継承チェーンが長くなるにつれて、メソッドやプロパティがどこから来ているのかを追跡するのが難しくなります
  1. 十分に柔軟ではない可能性がある「is-a」関係を強制されることになります
challenge icon

チャレンジ

ロボットを機能させるために、Robot.js ファイルを完成させてください。現在、ロボットは組み立てられていますが、何もすることができません。

Robot.js で行うこと:

  1. Robot のコンストラクタ内で、speaker コンポーネントと mover コンポーネントを作成します。
  2. 各メソッドでコンポーネントを使用します:
    1. greet() 内で:this.speaker.speak("Hello!"); を呼び出します。
    2. walkForward() 内で:this.mover.move("forward"); を呼び出します。

これを行う理由: これはコンポジション(合成)です。ロボットは、より小さなコンポーネントを組み合わせることで構築されています。ロボットはこれらの能力を継承するのではなく、スピーカーを持っており(has-a)(話すため)、ムーバーを持っています(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;
  }
}

深い継承の問題点:

  • 基底クラスへの変更が、予期せず子クラスを壊す可能性がある
  • メソッドやプロパティがどこに由来するのかを追跡するのが困難
  • 柔軟性に欠ける硬直した「is-a」関係を強制する

代替案としてのコンポジション: 継承の代わりに、オブジェクトがコンポーネントとhave-a関係を持つコンポジションを使用し、小さなパーツを組み合わせて機能を構築します。

自分で試してみよう

import { Robot } from './Robot.js';

const myRobot = new Robot('Robo');

myRobot.greet();     // 次のように出力されます: Saying: "Hello!"
myRobot.walkForward(); // 次のように出力されます: Moving forward
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン