【Java】アクセス修飾子の公開範囲を広げたオーバーライドの事例

Java

はじめに

OCJ-Pの試験勉強をしていると、継承について学習することになります。そして、継承の学習要素として「オーバーライド(Override)」が出てきます。その際、オーバーライドの仕様として「派生先ではメソッドの公開範囲を広げることができる」のですが、事例のようなものが見つからず、イメージするのに少し困ったので事例を自作しました。

事例

車のエンジン開始を例にとって作成しています。

登場するオブジェクトなど

パッケージ

以下の2つのパッケージを用意しています。

  • 車関係のオブジェクトを持つ「car」パッケージ
  • 車を操作したい「driver」パッケージ

クラス

以下の3つのクラスを用意しています。

  • Car クラス:スーパークラス。車種はなく、車の共通的な部品を持つ。
  • Fit クラス:Carクラスのサブクラス(ホンダ・フィットより命名)他クラスから操作される。
  • Driverクラス:Car、Fitを操作しようとするクラス

注意

サブクラスに「Fitクラス」と名付けたのは、筆者がHONDA党である以外の理由が無いです。なので、サンプルの図やコードは「Fit」になっていますが、お好きな車種に置き換えてお読みください。

クラスの図解

Carクラスと、Fitクラスの関係は以下の図の通りの構成としています。

そもそものお話

アクセス修飾子「protected」は、サブクラスまたは同一パッケージのクラスからのみアクセスを許容する修飾子です。

クラスの説明

  • Carクラスでは、エンジンを開始するメソッド「startEngine」を持っています。
  • Carクラスを継承したクラスでしか使用してほしくないので、Carクラスでは「startEngine」のアクセス修飾子を「protected」にしています。
  • Fitクラスでは、スーパークラスの「startEngine」をオーバーライドして、Fit専用のエンジン開始処理を作成しています。
  • Fitクラスは、利用者にエンジンを開始してもらいたいので、メソッドのアクセス修飾子を「public」にしています。

なぜスーパークラスとサブクラスでアクセス修飾子を変えているの?

今回の事例では、「Car」という漠然としたクラスと、「Fit」という明確な車種を示すクラスを用意しています。具体的な車種が設定されていないCarクラスで、エンジン開始の操作を行われても困ってしまいます。したがって、外部のパッケージから操作することができないように、スーパークラスのメソッドは公開しない設計にしています。

逆に、Fitクラスに「startEngine」をオーバーライドする際に、アクセス修飾子をprotectedにしたままだと、外部のパッケージから操作ができなくなります。(フィットのエンジンをかけることができない)そうなると、想定していた動作(外部のパッケージでもエンジンをかけてよい)を行うことができません。

外部パッケージからのアクセス

イメージ図

driverパッケージのDriverでCarクラスとFitクラスのオブジェクトを作って、startEngineを実行しようとしている図です。

上のDriverは、CarのstartEngine()を実行しようとしますが、CarのstartEngineは外部パッケージに公開されていませんので、操作できません。

下のDriverは、FitのstratEngine()を実行します。こちらはpublicなのでDriverは無事エンジンを開始することができました。

サンプルコード

Cars.java

package cars;

class Car {
  private boolean engineStatus = false;

  protected void startEngine() {
    startFunc();
    engineStatus = true;
  }
  private void startFunc() { // なんかいろんな処理 }
}

// ホンダ・フィット
class Fit extends Car {
  @Override
  public void startEngine() {
    super.startEngine();
    // Fitクラス固有のエンジン開始処理(コード省略)
  }
}

Driver.java

package driver;

import cars.Car;
import cars.Fit;

public class Driver {
  public static void main(String[] args) {
    Fit fit = new Fit();
    fit.startEngine();

    Car car = new Car();
//    car.startEngine(); //・・・protectedなので外部パッケージからはアクセスできない。
  }
}

最後に

あまりにも事例が見つからず、拙い事例ですが作成してみました。少しでもイメージ形成に役立てればいいなぁと思います。

ひとこと

事例を作っておいてなんなんですが、実務でこの設計をするかといわれると、おそらくやらないと思いますね。。。Interface使うとか、抽象メソッドにして実装は任せてしまうようなほうがよいかなぁと個人的には感じました。

コメント

タイトルとURLをコピーしました