さらなる拡張 : 多重継承

オブジェクト指向でテレビを作る


テレビ電話の登場

さて、文字放送付きテレビの設計も順調に終わり、TVクラスのユーザも増えたある日、今度は、テクノロジーの進化により、「テレビ電話」というものを作ってくれ、という要求がユーザから来ました。このテレビは、現在言われているような、「相手が見える電話」だけではなく、実際のテレビ(チューナー)としての機能も持っているものとします。つまり、電話をしながら相手の顔をみることもできるし、電話していない時はそれでテレビも見れる、という代物です。ここでは、大前提として、基本となる「TVクラス」と「電話クラス」の変更はしない、という方針でテレビ電話の設計をする、ということにしました。

さて、今度はこれをどのように設計するのでしょうか。前回までのように、「TVクラスから継承すれば良い」のは当然なのですが、今度は電話付きです。すでに別の電話クラスというものがあり、「TV電話クラス」は、それからも派生させなくてはいけないのです。

この時、「テレビ電話」の立場は、「テレビでもあり、電話でもある」という複雑なものです。これをJavaで実現させなくてはいけないのです。残念ながら、Javaの仕様では、一つのクラスから継承できるクラスは一つだけです。どうすれば良いのでしょうか?

多重継承

Javaでは、C++のように簡単に多重継承させることはできません。Javaによる多重継承には、いくつかの方法がありますが、一つのクラスに複数のクラスの機能を継承させるには一番簡単な方法としては、この「テレビ電話」の例で言えば、例えば、「”TV”の機能を継承し、”電話”の機能を実装する」、というようにする方法があります。まず、この例で考えてみましょう。

電話クラス

「テレビ電話」の基本となる電話クラスは次のようなものとします。



public class Phone {

  private int m_nNumber;//電話番号

  private int m_nVolume;//音量

//電話をかける

  public void Call (int nNumber) {

    m_nNumber = nNumber;

  }

//電話を取る

  public void Receive () {

    System.out.println("Hello!");

  }

//電話のボリューム調整

  public void Volume (int nNewVolume) {

    m_nVolume = nNewVolume;

  }

}

・・・どうも、電話らしくないですが、話を簡単にするためです。見逃してください。(^^;ここで注意しておきたいことは、この電話クラスにも、TVクラスと同じVolumeメソッド(音量調節メソッド)が存在していることです。

TVクラス

ここで使うTVクラスは、前の章までに作ってきたTVクラスをそのまま使うことにします。

テレビ電話クラス

ここでテレビ電話に求められていることは、「テレビ電話クラス」のユーザは、それを使う時に、Channel()などのTVクラスのメソッドとCall()などの電話クラスのメソッドを同じように使える、ということなのです。これを実現していきましょう。このテレビ電話は、基本的にはTVクラスの機能を継承し、電話クラスの機能を実装して作ることにします。

テレビ電話クラスを、次のようにして作ってみました。



public class TVPhone extends TV { 

  Phone myPhone = new Phone();

  public void Call() {

    myPhone.Call();

  }

  public void Receive() {

    myPhone.Receive();

  }

}

どうでしょうか?どうも不思議な気分ですね。まあ、とりあえずこれでやってみましょう。最初にPhoneクラスのオブジェクトを作成していることに注意。

ユーザは、次のようにしてこのテレビ電話を使うことが出来ます。



public static void main(String args[]) {

  TVPhone myTVPhone = new TVPhone();

  myTVPhone.Channel(12);

  myTVPhone.Call();

  myTVPhone.Volume(10);

  myTVPhone.Receive();

}

さあ、ここまで来た所でふと疑問が湧いてきます。myTVPhone.Volume()とは、なんのボリュームを調整するものなのでしょうか?電話でしょうか?テレビでしょうか?

答えは、「TVクラス」のVolume()メソッドです。TVPhoneクラスは、TVクラスを継承しているからです。では、「電話クラス」のVolume()メソッドは、どのようにして使えば良いのでしょうか。ここで思い出したいことは、TVPhoneクラスでまず初めにPhoneクラスのオブジェクトを作成したことです。これを使えば、Phoneクラスのメソッドが呼び出せるはずです。

PhoneクラスのVolumeメソッドは、このようにして呼び出すことが出来ます。



public static void main(String args[]) {

  TVPhone myTVPhone = new TVPhone();

  myTVPhone.myPhone.Volume(10);//電話のボリュームを調整する

}

・・・どうでしょうか?テレビ電話のユーザとしては、少し使いづらくなった感じです。しかし、テレビのボリュームと電話のボリュームが別にあってもおかしくはないはずです。スーパークラスのメソッドが重なった場合は、このようにすれば、混乱を避けることができます。

一連のテレビ電話ユーザの行動は、次のようになります。



public static void main(String args[]) {

  TVPhone myTVPhone = new TVPhone();

  myTVPhone.Channel(12);//テレビのチャンネルを変える

  myTVPhone.Volume(7);//テレビのボリュームを調整する

  myTVPhone.Call();//電話をかける

  myTVPhone.myPhone.Volume(10);//電話のボリュームを調整する

  myTVPhone.Receive();//電話を受ける

}

ここで、myTVPhone.Call(int)やmyTVPhone.Receive()は、オーバーライドメソッドです。その実体は、ただ単にPhoneクラスのメソッドをそのまま呼び出すためのメソッドとなっています。これは、テレビ電話ユーザが、Call()の呼び出しがPhoneクラスのメソッドを呼び出していると感じさせないためだけの存在です。

よって、スーパークラスのメソッドをオーバーライドする必要が無い場合には、TVPhoneクラスは、これだけでも良いわけです。



public class TVPhone extends TV { 

  Phone myPhone = new Phone();

}

このクラスのユーザは、テレビ電話を次のようにして使用します。



public static void main(String args[]) {

  TVPhone myTVPhone = new TVPhone();

  myTVPhone.Channel(12);//テレビのチャンネルを変える

  myTVPhone.Volume(7);//テレビのボリュームを調整する

  myTVPhone.myPhone.Call(057123445);//電話をかける

  myTVPhone.myPhone.Volume(10);//電話のボリュームを調整する

  myTVPhone.myPhone.Receive();//電話を受ける

}

・・・どうなんでしょうか?ここまでするとさすがに意味が無いように思われます。しかし、実際に多重継承する場合には、普通は何かしらオーバーライドやオーバーロードする関数があるんでしょうから、この方法ばかりではないでしょう。

とりあえず、一つのクラスから複数のクラスのメソッドなどを呼び出すための参考にはなると思います。


Mail me to WebMaster