サブクラス化によるクラスの再利用

今宣言したaircraftクラスは固定翼機ならどんな航空機にも使える。しかし熱気球やヘリコプタのオブジェクトも作りたくなる。この目的にはもはや現行のクラスは適当ではない。それは航空機の大きさを翼幅で規定しているからである。これは熱気球やヘリコプタには当てはまらない。気球の大きさは通常その体積で規定するし、ヘリコプタの大きさは回転翼の大きさで決まる。さあここでオブジェクト指向プログラミングの出番である。気球は多くの面で他の航空機と似た性格を持っており、航空機の特殊なものと考えられるので、新しく作る気球クラスは航空機クラスの全ての特徴と振る舞いとを継承し、もとのクラスと異なるメッドだけを置き換えればよい。例えば気球の大きさを出力するメソッドなどである。

他のクラスの特徴を継承しつつ、新しいクラスを生成する仕掛をサブクラス化と呼ぶ。Object REXXでサブクラスを作るには、クラスの宣言の際、いわゆる親クラスないしスーパークラスを指定すればよい:。


/*******************************************************/
/* Declare the balloon class as a subclass of aircraft.*/
/* balloonクラスをaircraftクラスのサブクラスとして宣言 */
/* する。                                              */
/*******************************************************/

::CLASS Balloon SUBCLASS Aircraft
現存のクラスをサブクラス化すると、新しいクラスは親クラスの全ての振る舞いを継承する。新しいメソッドを追加したり、現存のメソッドを再定義したりしない限り、名前を別として2つのクラスに差はない。何か違いをつけるため、気球の色をクラスの属性に追加し、初期化時の第4のパラメタとしよう。親クラスの他の初期化操作を再利用するにはメッセージを転送(forward)すればよい:

/*******************************************************/
/* Declare the INIT method for new balloons.           */
/* Four arguments will be processed and stored in the  */
/* object's instance variables:                        */
/* 気球 balloon 用のINITメソッド宣言。4つの引数が処理 */
/* され、インスタンス変数に保管される:                 */
/*      1. Registration of aircraft                    */
/*      2. Type of aircraft                            */
/*      3. Size (volume)  大きさ(体積)               */
/*      4. Color  色                                   */
/*******************************************************/
::METHOD INIT
  /* get access to instance variables */
  Expose Color

  /* read parameters into variables */
  Use Arg Registration, Type, Volume, Color

  /* forward parameters to parent initialization */
  /* 親に初期化パラメタを転送する */
  Forward Class(Super) Array(Registration, Type, Volume)
これを見て判るとおり、色 colour だけがインスタンス変数としてEXPOSEされている。他の属性は、FORWARD命令を用いて親にINITメッセージを転送することで親クラスに保管される。このFORWARD命令は、現行のメッセージを指定されたクラス(ここではスーパークラス)に指定のパラメタ(ここでは既にaircraftクラス向けに定義されている3つ属性の配列)とともに転送する。これらの属性は親クラスに置いたままなので、今回のサブクラスからも直接アクセスすることはできない。他のクラスのスコープに含まれる変数にアクセスするには、アクセス用のメソッドを定義する必要がある。

この例ではSTRINGメソッドの振る舞いを気球の体積を立方フィートで報告するよう変更したい。aircraftクラスのSTRINGメソッドを変更する一番容易なやり方は、別のクラスメソッドを定義して、それが返す文字列を利用するようにクラスを構築することである。balloonクラスではこの文字列を返す関数を再定義すればよい。aircraftクラスとballoonクラスとの唯一の相違点は航空機と気球の大きさを表す文字列である。そこで、SIZESTRINGというメソッドをaircraft、balloonの両方のクラスに実装して、それぞれの大きさを文字列にして返せばよい。さらに、balloonクラスからaircraftクラスのSize属性をアクセスできるように、SIZEメソッドを定義する必要もある。テストプログラムに、次のような変更/追加をせよ:


/* in the aircraft class add or change the following   */
/* methods                                             */
/* aircraftクラスで次のメソッドに変更ないし追加をせよ  */

/*******************************************************/
/* Declare the SIZESTRING method for the aircraft      */
/* class. It will return the aircrafts size formatted  */
/* as a string.                                        */
/* aircraftクラスにSIZESTRINGメソッドを宣言する。これは*/
/* 航空機の大きさを文字列で返す                        */
/*******************************************************/
::METHOD SizeString
  Return "a wingspan of" Self‾Size "feet"

/*******************************************************/
/* Declare the SIZE method. It will return the size    */
/* attribute of the aircraft (regardless of the        */
/* measurement).                                       */
/* SIZEメソッドを宣言する。aircraftクラスのsize属性を、*/
/* 単位に拘わらず返す                                  */
/*******************************************************/
::METHOD Size
  Expose Size
  Return Size

/*******************************************************/
/* Declare the STRING method for the aircraft class.   */
/* Return a string using the object's instance         */
/* variables.                                          */
/* STRINGメソッドをaircraftクラスに宣言する。オブジェク*/
/* トのインスタンス変数を使って文字列を返す。          */
/*******************************************************/
::METHOD String
  /* get access to the following instance variables    */
  Expose Registration Type

  Return "A" Type "(" || Registration,
         || ") with" Self‾SizeString
結果として返される文字列は以前の物と同じであるが、今や現行のクラスによって異なる値を返す事ができる。balloonクラスでSIZESTRINGメソッドを再定義すると、容易にSTRINGメソッドの返り値を変更することができる。サブクラスでメソッドの再定義を行う処理を、メソッドのオーバーロード(上書き)という。balloonクラスには、次のような追加を行う:

/*******************************************************/
/* Declare the SIZESTRING method for the balloon       */
/* class. It will return the balloon's volume          */
/* formatted as a string                               */
/* SIZESTRINGをballoonクラス用に宣言する。気球の体積を */
/* 文字列として返す。                                  */
/*******************************************************/
::METHOD SizeString
  /* format the string using the size method of the    */
  /* parent class                                      */
  /* 親クラスのsizeメソッドを使って文字列を書式化する。*/
  Return "a volume of" Self‾Size "cubic ft"
これで、balloonクラスのオブジェクトを生成し、体積を出力できる:

myBalloon = .Balloon‾New("N6148R", "Cameron", 120000,,
                         "yellow")
say myBalloon
次のような出力が得られるであろう:

A Cameron (N6148R) with a volume of 120000 cubic ft
これで気球の大きさは立方フィートで正しく報告されるようになったが、依然として色の属性が無視されたままである。出力に色属性を加えるには、なにもballoonクラスのSTRINGメソッドを全部書き直すには及ばない。再びスーパークラスのメソッドを再利用し、これに新しい属性を加え出力とすればよい。balloonクラスのSTRINGメソッドは次のようになろう:

/*******************************************************/
/* Declare the STRING method for the balloon class.    */
/* Return a string using the object's instance         */
/* variables.                                          */
/* STRINGメソッドをballoonクラスに宣言する。オブジェク */
/* トのインスタンス変数を使って文字列を返す。          */
/*******************************************************/
::METHOD String
  Expose Color

  /* reuse the string generated by the super class and */
  /* append the color of the balloon                   */
  /* スーパークラスで生成された文字列を再利用し、気球の*/
  /* 色を加える                                        */
  Return Self‾String:Super || ", color" Color
上記のメソッドではスーパークラスにメッセージを転送するもう一つのやり方を示している。結果を返さないFORWARD命令を利用する代りに、STRINGメッセージを明示的にスーパークラスに送り付け、その結果に気球の色を加えて出力とする。プログラムの実行結果はこうなる:

A Cameron (N6148R) with a volume of 120000 cubic ft, color yellow

[ Previous page | Next page | Tutorial Index | ]