オブジェクト指向プログラミングにおける継承の仕組みと設計上の注意点

こんにちは。ゆうせいです。

新人研修中に受講者から以下の質問をいただきました。

なぜ、継承は推奨されない場合があるのですか?

今回はこの質問に答えたいと思います。

オブジェクト指向プログラミングの主要な機能の一つに継承があります。継承は既存のクラスの機能を新しいクラスへ引き継ぐ便利な仕組みですが、不用意に利用するとシステムの保守性を著しく低下させる要因となります。今回は、Javaを用いた具体的な事例を通して、継承が抱えるデメリットと設計上のリスクについて解説します。

継承の基本概念と目的

継承とは、あるクラス(親クラス)が持つメソッドや変数を、別のクラス(子クラス)が受け継ぐ仕組みを指します。Javaでは extends キーワードを用いて実現します。

この仕組みを高校の部活動に例えると、運動部という共通のルール(親クラス)を、野球部やサッカー部(子クラス)が引き継ぐようなものです。どの運動部も共通して「練習する」「試合に出る」という振る舞いを持っていますが、これらを各部活動で個別に定義するのではなく、運動部という土台で一括して定義することで、記述の重複を避けることができます。

継承による密結合のリスク

継承の最大のデメリットは、親クラスと子クラスの関係が非常に強固になってしまうことです。これを専門用語で密結合と呼びます。

親クラスの内部実装を変更すると、その影響がすべての子クラスに波及します。例えば、親クラスのメソッドの仕様を変更した場合、子クラス側で予期せぬ動作不良が発生したり、コンパイルエラーが起きたりする可能性があります。

Javaによる具体例

以下のプログラムは、スマートフォンの基本機能を持つ親クラスと、それを継承した最新機種のクラスを表しています。

class SmartPhone {
    void call() {
        System.out.println("電話をかけます");
    }
    
    void sendMail() {
        System.out.println("メールを送信します");
    }
}

class NewModel extends SmartPhone {
    @Override
    void sendMail() {
        super.sendMail();
        System.out.println("高画質画像を添付します");
    }
}

ここで、開発者が親クラスである SmartPhone の sendMail メソッドの名称を sendMessage に変更したと仮定します。すると、子クラスである NewModel の @Override 指定をしている箇所でエラーが発生し、修正を余儀なくされます。このように、親の変化が子に強制的な修正を迫る状態が、継承の構造的な弱点です。

カプセル化の破壊

継承は、オブジェクト指向の重要な原則であるカプセル化を損なう可能性があります。カプセル化とは、クラスの内部状態を外部から隠蔽し、安全に操作できるようにする仕組みです。

しかし、子クラスは親クラスの内部構造(protected 指定された変数など)に直接アクセスできてしまうため、親クラスが意図しない形でデータが書き換えられるリスクが生じます。親クラスがどれほど堅牢に設計されていても、子クラスの振る舞いによってその安全性が崩されてしまうことを「脆弱な基底クラス問題」と呼びます。

継承のデメリットを整理する

継承を利用する際に考慮すべき具体的なデメリットを整理します。

  1. 柔軟性の欠如Javaでは一つのクラスしか継承できない単一継承の制約があるため、一度継承関係を結ぶと、後から別の親クラスに切り替えることが困難になります。
  2. 階層の複雑化機能を追加するたびに継承を繰り返すと、クラスの階層が深くなります。階層が深くなると、あるメソッドの実態がどのクラスで定義されているのかを追跡することが難しくなり、解読性が低下します。
  3. 不要な機能の継承親クラスに定義されたすべての公開メソッドが子クラスに引き継がれるため、子クラスにとって不要な、あるいは公開すべきでない機能まで外部に露出してしまいます。

継承と委譲の比較

実務では、継承のデメリットを回避するために委譲という手法が推奨される場面が多くあります。委譲とは、他のクラスを継承するのではなく、そのクラスのインスタンスを変数として保持し、必要な時だけ呼び出す方法です。

委譲を用いることで、クラス間の関係は緩やか(疎結合)になり、内部実装の変更による影響を最小限に抑えることが可能になります。

まとめ:学習のステップ

オブジェクト指向の学習を深めるためには、以下の順序で理解を進めることを推奨します。

  1. クラスの基本構造と、カプセル化による情報隠蔽の重要性を正しく理解してください。
  2. 継承によってコードの再利用性が高まる場面と、今回説明した保守性の低下を招く場面を比較してください。
  3. 継承の代替案として語られる「インターフェース」の活用や「委譲」のパターンを学び、設計の選択肢を広げてください。

機能を実現することだけでなく、数年後のメンテナンスが容易であるかどうかを常に意識して、クラス設計に取り組んでいきましょう。

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。