Rubyのオブジェクト指向におけるクラスとモジュール、継承、Mixin、アクセス制御の使い方若手エンジニア/初心者のためのRuby 2.1入門(7)(2/5 ページ)

» 2014年08月28日 18時00分 公開
[著:麻田優真、監修:山根剛司株式会社アジャイルウェア]

オブジェクトの「振る舞い」。メソッドを定義してみる

 ここまでの説明でRabbitクラスを定義しましたが、メソッドを何も定義していないので、このままではウサギを表すクラスとしては不適切です。そこで、いくつかメソッドを定義してみます。

class Rabbit
  def jump
    puts "pyon! pyon!"
  end
 
  def pound_steamed_rice_into_rice_cake
    puts "pettan! pettan!"
  end
end
rabbit.rb
require_relative "rabbit"
 
rabbit1 = Rabbit.new
 
rabbit1.jump
rabbit1.pound_steamed_rice_into_rice_cake
main02.rb

クラスにメソッドを定義するdef〜end

 「def」式を用いると、クラスにメソッドを定義できます。「def [メソッド名]」から始まり、「end」までの間に所望の処理を書きます。ここでは、ウサギを跳ねさせる「Rabbit#jump」メソッドを定義しており、「puts」メソッドを使ってターミナルに「pyon! pyon!」という文字列を出力しています。「Rabbit#pound_steamed_rice_into_rice_cake」メソッドも同様に、ターミナルに文字を出力します。

オブジェクト.メソッド名で呼び出す

 メソッドを利用する場合は、main02.rbの5行目と6行目のように、オブジェクトに.(ドット)を続け、メソッド名を書きます。

 では、main02.rbを実行してみましょう。Rabbitクラスのオブジェクトであるrabbit1のメソッドがきちんと呼ばれていることを確認してください。

$ ruby main02.rb 
pyon! pyon!
pettan! pettan!
main02.rbの実行結果

補足「インスタンスメソッドとクラスメソッド」

 ここまで説明してきたのは、オブジェクトに対するメソッドであるインスタンスメソッドでした。その他にも、クラスそのものに対してメソッドを定義することもできます。「Rabbit.new」というのも、実はRabbitクラスそのものに定義された「クラスメソッド」なのです。

 クラスやモジュールに関するメソッドの入り組んだ話は、メタプログラミングを理解するために必要です。ですので、この辺りのややこしい部分は以降の連載であらためて解説することとして、ここでは割愛します。


オブジェクトの「状態」。インスタンス変数

 前節で、メソッドを定義することで、クラスに何らかの振る舞いをさせることができることを学びました。では、オブジェクトごとに状態を持たせるためにはどうしたらよいのでしょうか?

 答えは、インスタンス変数という仕組みを使うことです。以下、Rabbitクラスのオブジェクトに、ウサギの名前を表す「name」、毛の色を表す「color」、耳の長さを表す「length_of_ears」という状態を持たせる例です。記述量が増えてきて、だんだんとクラスらしくなってきました。

class Rabbit
  attr_accessor :name
  attr_reader :color, :length_of_ears
 
  def initialize(name: "usachan", color: :white, length_of_ears: 10)
    @name = name
    @color = color
    @length_of_ears = length_of_ears
  end
 
  def jump
    puts "pyon! pyon!"
  end
 
  def pound_steamed_rice_into_rice_cake
    puts "pettan! pettan!"
  end
  
  def say_name
    puts "Hello, I'm #{@name}!"
  end
end
rabbit.rb
require_relative "rabbit"
 
rabbits = []
 
rabbits.push(Rabbit.new)
rabbits.push(Rabbit.new(name: "pyonkichi"))
rabbits.push(Rabbit.new(name: "inaba", color: :brown, length_of_ears: 7))
 
rabbits.each do |rabbit|
  puts rabbit.name
  puts rabbit.color
  puts rabbit.length_of_ears
  rabbit.say_name
  puts ""
end
 
rabbits[0].name = "wooser"
puts rabbits[0].name
main03.rb

コンストラクター、インスタンス変数、キーワード引数

 まずはrabbit.rbから見ていきましょう。2行目から9行目および、Rabbit#say_nameメソッドが、ここでの変更で追記した部分です。

 Rabbitクラスのオブジェクトを生成するときに「Rabbit.new」というクラスメソッドを使いますが、このときに「Rabbit#initialize」というメソッドが呼ばれます。このように、オブジェクトが生成される時に実行されるメソッドを「コンストラクター」と呼び、一般的にはオブジェクトの状態を初期化するようなコードをコンストラクターに含めます。

 コンストラクターの中、5行目から9行目にかけて、オブジェクトの状態を初期化しています。「@name」などの「@(アットマーク)」から始まる変数は「インスタンス変数」と呼ばれ、オブジェクトの状態を保持します。

 ここで、Rabbit#initializeメソッドの定義にさりげなく「キーワード引数」というテクニックを使っています。キーワード引数を使うことで、main03.rbの7行目のようにどの引数がどのインスタンス変数に対応しているのかが分かりやすくなります。また、デフォルト値を設定しているので、main03.rbの5行目と6行目のように、引数を省略できます。

 インスタンス変数はRabbitクラスの任意のメソッドから読み取りや代入を行うことができます。ここでは、「Rabbit#say_name」の中で「@name」を利用しています。

「属性」を定義するattr_accessorメソッド、attr_readerメソッド

 実はインスタンス変数に代入しただけでは、オブジェクトの外からその値を利用できません。そのために、Rubyでは属性を定義するためのメソッドを利用します。

 2行目のように、「attr_accessor」メソッドにインスタンス変数の名前に対応する「シンボル」を与えると、そのインスタンス変数はオブジェクトの外から属性として読み書き可能となります。実際、main03.rbの17行目では配列「rabbits」の0番目のRabbitクラスのオブジェクトのnameを「wooser」という文字列で書き換えています。

 3行目は「attr_reader」メソッドを使っていますが、これはインスタンス変数が読み取り専用の属性であることを示します。「attr_reader」で設定したインスタンス変数を外部から書き換えることはできません。

main03.rbについて

 main03.rbは、3つのRabbitクラスのオブジェクトを生成し、それらを配列「rabbits」に格納しています。その後、9行目から16行目で、それぞれのオブジェクトに対して、「name(名前)」「color(毛の色)」「length_of_ears(耳の長さ)」をターミナルに出力し、「Rabbit#say_name」の動作もチェックしています。

 また、17行目で「attr_accessor」に設定したインスタンス変数「name」に新しい名前「wooser」を設定し、18行目で新たな名前が設定されたかどうかを確かめています。

 以下に、main03.rbの実行結果を示します。

$ ruby main03.rb 
usachan
white
10
Hello, I'm usachan!
 
pyonkichi
white
10
Hello, I'm pyonkichi!
 
inaba
brown
7
Hello, I'm inaba!
 
wooser
main03.rbの実行結果

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。