Rubyにおける継承とメッセージング
継承を利用すると、他のクラスの改良版や特殊化版として機能するクラスを作成することができます。例えば、ジュークボックスのシステムでは、Songクラスに「曲」という概念を内包していますが、市場の拡大に伴い、カラオケのサポートを提供する必要が出てきました。カラオケの曲は、他の曲と変わりません(リードボーカル・トラックがないだけなので、それを気にする必要はありません)。しかし、歌詞のセットと時間情報は含まれています。ジュークボックスがカラオケ曲を再生しているとき、歌詞はジュークボックスの前にあるスクリーン上で音楽とともにスクロールする必要があります。
この問題を解決する一つの方法は、歌詞付きのSongであるKaraokeSongという新しいクラスを定義することです。
class KaraokeSong <Song
def initialize(name,artist,duration,lyrics)
super(name,artist,duration)
@lyrics = lyrics
end
end
クラス定義の行にある "< Song" は、KaraokeSong が Song のサブクラスであることを Ruby に伝えるものです。したがって、これはSongがKaraokeSongのスーパークラスであることも意味します。
song = KaraokeSong.new("My Way","Sinatra",255,"And now, the ... ")
song.to_s -> *Song:My Way--Sinatra(225)*
to_sメソッドを呼び出すと、歌詞が表示されない
これは、オブジェクトにメッセージを送るときに、どのメソッドを呼び出すかを決めるRubyの仕組みと関係がある。プログラムコードの最初の解析(パース)の際、Rubyはsong.to_sというメソッド呼び出しに遭遇しても、to_sメソッドがどこにあるのかわからず、プログラムの実行が始まるまでその判断を先延ばしにしています。そこでRubyはsongが所属するクラスを調べます。もしそのクラスがメッセージと同じ名前のメソッドを実装していれば、そのメソッドを実行します。そうでなければ、Rubyはその親クラスのメソッドを調べ、さらにその祖先のクラスと、祖先の連鎖をさかのぼっていきます。もし先祖のクラスで正しいメソッドが見つからなければ、Ruby は特別な動作をします(通常はエラーを発生させます)。
この問題をKaraokeSong#to_sを実装することで解決してみましょう。まず、最もグルーブ感のある方法として、Songクラスからto_sメソッドをコピーして歌詞の情報を追加する方法から始めましょう。
class KaraokeSong
#...
def to_s
"KS: #@name--#@artist(#@duration){#@lyrics}"
end
end
song = KaraokeSong.new("My Way", "Sinatra", 225,"And now, the... ")
song.to_s ->"KS: My Way--Sinatra(225){And now,the...} "
インスタンス変数@lyricsの値を正しく表示できています。しかし、この方法を使うと、サブクラスは祖先のインスタンス変数に直接アクセスする必要があります。では、なぜこれがto_sを実装するのに悪い方法なのでしょうか?
その答えは、良いプログラミングスタイル(デカップリングと呼ばれることもあります)と関係があります。親クラスの内部構造に直接入り込み、インスタンス変数を見せつけるようなことをすると、親の実装に強く縛られることになります。
この問題は、各クラスに実装の詳細を任せることで解決します。KaraokeSong#to_sを呼ぶときは、親クラスのto_sメソッドを呼んで、曲の詳細を取得します。そして、そこに歌詞の情報を付加して結果を返しています。パラメータなしで super を呼び出すと、Ruby は現在のオブジェクトの親クラスにメッセージを送り、子クラスの同じ名前のメソッドを呼び出すように依頼します。これで、新しく改良された to_s メソッドを実装することができます。
class KaraokeSong <Song
#Format ourselves as a string by appending
#our lyrics to our parent's to_s value.
def to_s
super+"{#@lyrics}"
end
end
song = KaraokeSong.new("My Way", "Sinatra" ,225, "And now, the... ")
song.to_s ->"Song:My Way--Sinatra(225){And now,the...} "
KaraokeSong は Song のサブクラスであることを Ruby に明示していますが、Song クラスの親クラスが何であるかは明示していません。親クラスを指定せずにクラスを定義すると、Ruby はデフォルトで Object クラスを親として扱います。つまり、すべてのクラスの始祖は Object であり、Object のインスタンスメソッドはすべての Ruby オブジェクトで利用可能です。
関連
-
redisクラスタ構築のチュートリアルと発生した問題
-
画像フィルターアルゴリズムコードのRuby実装
-
Ruby on RailsのWebプロジェクト構築のためのシンプルガイド
-
RubyのHash構造体の基本操作のまとめ
-
Rubyのオブジェクト指向のアプローチによるプログラミング学習雑学
-
Jekyll静的ウェブサイトのバックエンドエンジンのチュートリアル
-
Nokogiriパッケージを使ってXML形式のデータを操作するためのRubyチュートリアル
-
Rubyのデザインパターン。プログラミングにおけるアピアランスパターンの応用
-
Rubyのプライベートとプロテクトを簡単にご紹介します。
-
RubyGnome2 ライブラリを用いた GTK 環境での Ruby GUI プログラミングの基本的な考え方
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Rubyの二分探索(dichotomous search)アルゴリズムの簡単な例
-
挿入ソートアルゴリズムのRuby実装と高度な双方向挿入ソートコード例
-
Rubyフックメソッド使用例
-
Ruby on Rails ラックミドルウェア基礎学習チュートリアル
-
Ruby on Railsフレームワークの設計構造をMVCマインドで理解する
-
MongoDBに接続するためのRuby on Railsフレームワークアプリケーション チュートリアル
-
Rubyブロックチュートリアル
-
Ruby on Railsで構築するアプリケーションの基本的なディレクトリ構造のまとめ
-
Ruby on Railsのパフォーマンスを最適化するためのいくつかの方法についての考察
-
Rubyプログラミングにおけるアサインメント関連操作