RubyOnBasis[02] 新人Railsエンジニア向け講座

このシリーズについて

RubyOnBasisはRuby on Railsを業務に利用する新人Webエンジニアのための、Railsを使わないテキストだ。この講座ではWEBrickを使ってWebアプリを書きながらHTTPを始めとする基礎知識をキャッチアップしてRailsがどうやって作られ動くのかを理解していく。

このシリーズを始めから読む

クラスの継承

前回はクラスとインスタンスの話をした。覚えているかな? クラスがメソッドという振る舞いの情報を持ち、インスタンスが状態の情報を持つというのが要点だ。

今回の話題は「継承」について。オブジェクト指向プログラミングでは非常に重要な概念となる。何故なら継承がコードの再利用をしやすくするからだ。

では、継承とは一体なんなのか。よく言われる説明では既存のクラスを元にして構造や振る舞いを共有した別のクラスを作るということだ。

ここでは、ちょっと違う表現もしてみよう。継承とは、あるクラスが持つ振る舞いの情報を別のクラスから参照することだとも言える。 (ややこしくなるから詳しい話はしないが、継承の概念自体はクラス以外にも適用される)

継承を書いてみよう!

前回書いたArticleクラス君のことは覚えているかな? 今回も彼に登場してもらおう。

class Article
  def set_body(text)
    @body = text
  end

  def get_body
    @body
  end
end

class CommercialArticle < Article
  def get_body
    "#{@body} (提供: Owl Works)"
  end
end

new_ca = CommercialArticle.new
new_ca.set_body('奇麗は汚い、汚いは奇麗!')
puts new_ca.get_body
#=> 奇麗は汚い、汚いは奇麗! (提供: Owl Works)

では読んでみよう。CommercialArticleクラスは商業用の記事を表現するためのクラスだ。なので本文を出力する時にはスポンサーの名前がついてくるよ。

見ての通り、このクラスはArticleクラスを継承している。これによってArticleで定義されたメソッドは全て利用することが出来る。

ちなみにこういった継承関係にあるクラス同士について、Articleクラスを基底クラスまたは親クラス、スーパークラスなんて呼ぶんだ。逆にCommercialArticleクラスのことを派生クラス、子クラス、サブクラスとか言うね。

さて、set_bodyメソッドは継承したそのままで利用しているが、get_bodyメソッドについては派生クラスで独自に定義し上書きしている。

素晴らしきかな、継承

冒頭に話したことを覚えてる? 継承はコードの再利用をしやすくすると説明したよね。CommercialArticleはset_bodyメソッドをわざわざもう一個書いてメンテナンスをするという手間を省いてくれた。

その上、利用するときは普通のArticleと同じように本文(body)のデータが欲しければget_bodyメソッドを呼び出すだけでいい。

こう言う構造になっていると、他のオブジェクトが処理内で記事オブジェクトの本文を利用したいと思った時にも便利だよね。その記事オブジェクトが普通のArticleクラスなのかCommercialArticleクラスなのかを気にする必要はなくて、とにかくget_bodyメソッドを使えばどちらのクラスであれ本文データを得られるんだから。

この便利な使い方には ポリモーフィズム(多態性) という名前がついていて、やはりオブジェクト指向プログラミングにおける重要な概念なんだ。でも、一度に複数のことを説明すべきではないから後でまた説明するね。

理解するために視る

次には、視ることを学べ。視ることに熟して、さて、小を視ること大の如く、微を見ること著の如くなったならば、来たって我に告げるがよいと。 (中島敦 - 名人伝)

ちょっとここで例によって継承関係をもっとわかりやすく見てみようか。

class Article
end

class CommercialArticle < Article
end

puts CommercialArticle.class.ancestors.join(' < ')
puts CommercialArticle.ancestors.join(' < ')

#=> Class < Module < Object < Kernel < BasicObject
#=> CommercialArticle < Article < Object < Kernel < BasicObject

classメソッドはクラスのクラスオブジェクトを返す。またancestorsメソッドはクラスがどういう継承関係になっているのかを配列で返してくれるメソッドだ。ancestorは訳すと"祖先"だね。さて、思ったよりもヤケに長いのがわかるだろう。

Moduleクラスといふもの

ObjectもKernelも重要なんだけど、ここではModuleクラスについてだけ説明しよう。すべてのクラスオブジェクトはModuleクラスを自動的に継承している。こいつは一体なにか?

その前に、賢明な読者の諸君なら今までの説明で疑問に思うことがあったんじゃないかな? そう、コードの中でancestorsメソッドとかnewメソッドとかをさんざん使って来たけど一度もこんなメソッドを定義した覚えはないよね。あなた! そのメソッドいったい誰の子よ!

じゃあ、こいつらは一体どこから来たのか? その答えがModuleクラスだ。これらのメソッドはModuleクラスで定義されているので、全てのクラスオブジェクトは自分で定義しなくてもnewメソッドやancestorsメソッドを利用することができる。

今回説明しなかったObjectやKernelについても、すごい雑に説明すると君が定義した覚えがないのに使えるほとんどのメソッドはObjectクラスとかModuleクラスが定義してくれていて、自動的に継承されるので使えるんだ。すごい!

メソッドというメッセージ

そうそう、ここでちょっと用語の説明を加えよう。メソッドを実行するオブジェクトのことを一般的にはレシーバ(receiver)って呼ぶんだ。受取手という意味だよ。例えばArticle.classのレシーバはArticleとなる。何を受け取るのかというと、メッセージだ。

メッセージって何??聞いたことがないよ!と慌てなくてもいい。何のことはない、今まで触れて来たメソッドというのが正にメッセージで、つまり「何々をせよ」というメッセージを受け取るのがレシーバってことオブジェクト指向プログラミングというのは、レシーバであるオブジェクトがメソッドというメッセージをやりとりするプログラミングなワケだ。

<< 前のチャプターへ戻る | 次のチャプターへ進む >>