はじめに
オブジェクト指向プログラミングの入門書では、動物の鳴き声を使ったサンプルをよく見ますね。
これは一見わかりやすく思えますが、どう実際のプログラムにあてはめればよいか、初心者の方はわかりにくいのではないかという気もしました。そこで本稿では、現実の物をオブジェクトとして扱うことで、オブジェクト指向について別の面から見ることに挑戦してみたいと思います。
オブジェクト指向の基礎
まず、サンプルから見ていきましょう。前回の往復プログラムを、railクラスを使って書き換えてみました(リスト2)。
「class rail {」のところがクラスの定義なのですが、今回は説明を割愛します。かわりに、railクラスの取扱説明書を書くとしたら、どうなるでしょうか。
- (1)あらかじめ「$r0 =& new rail("00");」としておきます。"00"はレールの番号です。
- (2)「$r0->drive(3);」とすると、レールに電圧がかかります。数字が大きいと、スピードも速くなります。ゼロだと停止で、マイナスだと逆方向になります。
- (3)「$r0->sense();」とすると、レールに車両があれば1、なければ0が返ります。
これにより、後半の制御部分ではレールの番号に依存しなくて済むようになりました。たとえば配線ミスがあってレールの番号を変えたくなったら、「new rail("00")」のところだけ変えれば、残りはそのままで大丈夫です。
さて、これだけなら配列変数でも良さそうですが、クラスを使うとコード部分も入れ替えることができます。
継承
たとえば、レールのプラスマイナスを逆に配線してしまい、プログラムの方で対応したいときは、どうしたらよいでしょう。このままでは車両が逆向きに走ってしまいますから、普通なら「$r0->drive(3);」の部分を全部マイナスにしないといけません。
こんなときオブジェクト指向では、railクラスの後に、以下のような新しいクラスを追加します。
短いわりにはわかりにくいリストですが、やっていることはシンプルです。「class revrail extends rail」の部分で、railクラスを拡張してrevrailにすることを宣言しています。内容はdriveメソッドの変更で、引数$speedをマイナスにして、親であるrailクラスのdriveメソッドに渡しています。
使い方は簡単で、さきほどの「$r0 =& rail("00");」のところを「$r0 =& revrail("00");」にするだけです。これで、$r0を使っているところは全部逆向きになります。もちろん、今まで通りrailクラスも使用でき、こちらは何も変わりません。
呼び出し方もrailクラスのときと同じです。「$r0->drive(3);」とすれば、$r0がrevrailクラスなら、-3にしてrailクラスに渡されることになります。使う側は、$r0がrailクラスなのかrevrailクラスなのかを知らなくてもまったく問題ありません。
これを応用すると、あるレールは別のコントローラにつながっているためコマンドが違うといった場合でも、スマートに対応することができます。新しいクラスであっても、railクラスと同じメソッドが用意されていれば、railクラスのかわりに使うことかできるためです。コントローラに送るコマンドはrailクラスの中だけで完結しているため、コマンドが変更されても、railクラスの定義を変えるだけで済むのです。
なお、オブジェクト指向の用語では、「revrailクラスはrailクラスを継承している」「revrailクラスではdriveメソッドをオーバーライドしている」などと呼んでいます。また、Javaのような厳密な型宣言を必要とする言語では、たとえrailクラスと同じメソッドを持っていても、railクラスを継承していない限りrailクラスのかわりに利用することはできません。
同時走行
説明が長くなってしまいました。では、実際にオブジェクト指向を使って、2つの車両を同時走行させてみましょう。とはいっても、それぞれのレールに通電すればよいだけなので、特にオブジェクト指向でないとダメということではありません。
ポイントで大きいループと小さいループが切り替わるようになっています。それぞれの車両が、小さいループと大きいループを交互に走ります。ダイヤグラムで書くと、図2のようになります。
プログラムはリスト4のようになりました。
ここではポイントもクラスにしてみました。ポイントは2つを対で動かすことが多いので、2つのポイントを登録できるようにしてあります。
今回も実行結果を動画で見てみましょう。
次回は、それぞれの車両をオブジェクトにしてみます。