Rubyのオブジェクト指向におけるクラスとモジュール、継承、Mixin、アクセス制御の使い方:若手エンジニア/初心者のためのRuby 2.1入門(7)(2/5 ページ)
オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。今回は、Rubyのにおけるクラスとモジュール、継承、Mixin、アクセス制御などの基本的な使い方について解説します。
オブジェクトの「振る舞い」。メソッドを定義してみる
ここまでの説明でRabbitクラスを定義しましたが、メソッドを何も定義していないので、このままではウサギを表すクラスとしては不適切です。そこで、いくつかメソッドを定義してみます。
class Rabbit def jump puts "pyon! pyon!" end def pound_steamed_rice_into_rice_cake puts "pettan! pettan!" end end
require_relative "rabbit" rabbit1 = Rabbit.new rabbit1.jump rabbit1.pound_steamed_rice_into_rice_cake
クラスにメソッドを定義する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!
補足「インスタンスメソッドとクラスメソッド」
ここまで説明してきたのは、オブジェクトに対するメソッドであるインスタンスメソッドでした。その他にも、クラスそのものに対してメソッドを定義することもできます。「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
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
コンストラクター、インスタンス変数、キーワード引数
まずは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
Copyright © ITmedia, Inc. All Rights Reserved.