初学者の私がRubyを学ぶ上でまず躓いたのがattr_accessorやinitializeメソッドだったので自分の中の整理の意味も含めて書いておきたいと思います。
attr_accessorを理解するためにはinitializeメソッドの理解が必要だと思うので先にそちらから書いていきます!因みに今回は例のポケモンを使って説明していきたいと思います。
目的
・ポケモン(Pokemon)というクラスを元に基本的な情報であるステータス(名前、体力、攻撃力、防御力)を持つリザードン(lizardon)を生み出す。(何でリザードン?かっこいいからにきm)
本編
1. クラス設定
まず、クラスの設定を行います。
class Pokemon
end
まずはクラスの定義からですね。ここからリザードンに必要な情報を書いていきます。
2. ステータスの設定(セッターの定義)
リザードンには名前(name
)、体力(hp
)、攻撃力(offense
)、防御力(defense
)の4つのステータスが存在しますので設定していきましょう。まず覚えるべき言葉が「セッター」です。セッターとは、簡単にいうと、ステータスの値を更新するためのメソッドです。
例えば、体力の更新するときはlizardon.hp = 500
のように =
を用いて値を代入します。そのため、メソッドを定義する際にもhp =(hp)
の形で記述することになります。
class Pokemon
# nameのセッター
def name=(name)
@name = name
end
# hpのセッター
def hp=(hp)
@hp = hp
end
# offenseのセッター
def offense=(offense)
@offense = offense
end
# defenseのセッター
def defense=(defense)
@defense = defense
end
end
hp = (hp)
の(hp)
は引数と呼ばれます。この引数に渡ってきた値がインスタンス変数@hp
に格納されます。もう少し具体的にみていきます。
class Pokemon
def name=(name)
@name = name
end
def hp=(hp)
@hp = hp
end
def offense=(offense)
@offense = offense
end
def defense=(defense)
@defense = defense
end
end
# ポケモンクラスをインスタンス化(lizardonが誕生)
lizardon = Pokemon.new
# lizardonのステータスに値を設定
lizardon.name = "リザードン"
lizardon.hp = 78
lizardon.offense = 84
lizardon.defense = 78
インスタンス化というのは、ポケモンクラスからステータスも何もを持たないまっさらなlizardon
が新しく生まれたと考えてください。そして、ステータスの設定で値が決まり、それがセッターの引数に渡され、最終的にインスタンス変数に渡るイメージです。
こうすることで各ステータスの値がインスタンス変数にセットされます。(故にセッター!)
3. ステータスの取得(ゲッターの定義)
セッターでは、リザードンのステータスの設定ができました。が、これではまだ値をセットしただけにすぎません。折角セットした値ですがこれを取り出すことができないと意味ないですね。そこで今回はこの値をゲットするという意味での「ゲッター」を作っていきましょう!
class Pokemon
def name=(name)
@name = name
end
# nameのゲッター
def name
@name
end
def hp=(hp)
@hp = hp
end
# hpのゲッター
def hp
@hp
end
def offense=(offense)
@offense = offense
end
# offenseのゲッター
def offense
@offense
end
def defense=(defense)
@defense = defense
end
# defenseのゲッター
def defense
@defense
end
end
ゲッターを定義できたので、実際に取り出してみましょう。
class Pokemon
def name=(name)
@name = name
end
# nameのゲッター
def name
@name
end
def hp=(hp)
@hp = hp
end
# hpのゲッター
def hp
@hp
end
def offense=(offense)
@offense = offense
end
# offenseのゲッター
def offense
@offense
end
def defense=(defense)
@defense = defense
end
# defenseのゲッター
def defense
@defense
end
lizardon = Pokemon.new
lizardon.name = "リザードン"
lizardon.hp = 78
lizardon.offense = 84
lizardon.defense = 78
# 値を取り出す
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
end
実行画面
リザードン
78
84
78
ゲッターを利用して値を取り出すことができましたね!
4. initializeメソッド
さて、いよいよinitialize
メソッドについての説明です。ここまで理解できていたらそこまで難しくありません!initialize
メソッドを簡単に説明すると、初期値の設定をするためのメソッドです。
具体的には次のようにします。
#初期値の設定
def initialize
@name = "リザードン"
@hp = 78
@offense = 84
@defense = 78
end
初期値の設定、これは実はさっきまでのコードで既に行っていました。該当の箇所はここです。
# lizardonのステータスに値を設定
lizardon.name = "リザードン"
lizardon.hp = 78
lizardon.offense = 84
lizardon.defense = 78
なのでこちらの部分はカットして、それに伴うセッターもカットしてしまいましょう。
class Pokemon
#初期値の設定
def initialize
@name = "リザードン"
@hp = 78
@offense = 84
@defense = 78
end
#ゲッターは残しておく
def name
@name
end
def hp
@hp
end
def offense
@offense
end
def defense
@defense
end
# ポケモンクラスをインスタンス化(lizardonが誕生)
lizardon = Pokemon.new
# 値を取り出す
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
end
因みに、このinitialize
メソッドはnew
メソッドでインスタンス化することでインスタンス変数に初期値がセットされますので忘れずにインスタンス化しましょう。
5. 自由なパラメータ設定
ここまでの内容では、initialize
メソッドは決まった値しかパラメータを設定できません。これを好きな値に変えてみたいと思います。
次のようにして準備しましょう!
各インスタンスごとに柔軟に値を設定できるように書き換えてみましょう。その際は、new
演算子に引数を渡して値を設定します。
class Pokemon
# new演算子から渡された引数を受け取る
def initialize(name:, hp:, offense:, defense:)
@name = name
@hp = hp
@offense = offense
@defense = defense
end
def name
@name
end
def hp
@hp
end
def offense
@offense
end
def defense
@defense
end
# パラメータの値をinitializeにキーワード引数として渡す
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
end
initializeに渡す引数はnew演算子において {name: "リザードン", hp: 78, offense: 84, defense: 78}
というようなハッシュの形式(キーとバリューの組み合わせ)となっています。そのため、initialize
に渡す引数もハッシュ形式で渡してあげましょう!
次のように書き換えられます。
class Pokemon
# 引数に**を記述:ハッシュしか受け取れなくなる
def initialize(**params)
@name = params[:name]
@hp = params[:hp]
@offense = params[:offense]
@defense = params[:defense]
end
def name
@name
end
def hp
@hp
end
def offense
@offense
end
def defense
@defense
end
# パラメータの値をinitializeにキーワード引数として渡す
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
end
こうすることでミスが起こりにくい記述になります。
6. アクセスメソッド(attr_reader)
実はこれまでに書いてきたセッターやゲッターの処理はもっと簡潔に記述できます。それがアクセスメソッドです。
先ほどのコードを次のように直してみましょう。
class Pokemon
# attr_readerの記述でゲッターを省略することができる
attr_reader :name, :hp, :offense, :defense
def initialize(**params)
@name = params[:name]
@hp = params[:hp]
@offense = params[:offense]
@defense = params[:defense]
end
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
end
次のような結果になるはずです。
リザードン
78
84
78
attr_reader
はゲッターの役割を果たすことが理解できたかと思います。
7. アクセスメソッド(attr_writer)
これで一旦、リザードンの初期パラメーターは表現できました。しかし、もう少し一工夫しましょう。リザードンのHPは敵から受けるダメージによって変化する可能性がありますよね?そのためHPの初期値から値が変化するようにコードを書き直していきましょう。
class Pokemon
attr_reader :name, :hp, :offense, :defense
def initialize(**params)
@name = params[:name]
@hp = params[:hp]
@offense = params[:offense]
@defense = params[:defense]
end
# セッターを再定義
def hp=(hp)
@hp = hp
end
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
lizardon.hp -= 30
puts "#{lizardon.name}はダメージを受けた! 残りHPは#{lizardon.hp}だ"
end
ここでセッターをまた定義することで lizardon.hp -= 30
によってHPの初期値(78)から30引かれた値(48)が再セットされます。
つまり最後の出力は次のようになるはずです。
リザードンはダメージを受けた! 残りHPは48だ
この流れをもっと簡潔にするためのものがattr_writer
です。
class Pokemon
attr_reader :name, :hp, :offense, :defense
# attr_writerでセッターを定義
attr_witer :hp
def initialize(**params)
@name = params[:name]
@hp = params[:hp]
@offense = params[:offense]
@defense = params[:defense]
end
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
lizardon.hp -= 30
puts "#{lizardon.name}はダメージを受けた! 残りHPは#{lizardon.hp}だ"
end
8. アクセスメソッド(attr_accessor)
いよいよ最後です。attr_reader
とattr_writer
を同時に定義できるメソッドがあるのです。それがattr_accessor
です。こちらを使えば、attr_readerとattr_writerの記述を1行で表すことができます。
class Pokemon
attr_reader :name, :hp, :offense, :defense
# セッターとゲッターを一括定義
attr_accessor :hp
def initialize(**params)
@name = params[:name]
@hp = params[:hp]
@offense = params[:offense]
@defense = params[:defense]
end
lizardon = Pokemon.new(name: "リザードン", hp: 78, offense: 84, defense: 78)
puts lizardon.name
puts lizardon.hp
puts lizardon.offense
puts lizardon.defense
lizardon.hp -= 30
puts "#{lizardon.name}はダメージを受けた! 残りHPは#{lizardon.hp}だ"
end
出力結果
リザードン
78
84
78
リザードンはダメージを受けた! 残りHPは48だ
##まとめ
initialize
は初期化
attr_reader
はゲッター
attr_witer
はセッター
attr_accessor
はセッターとゲッターの両方の機能
という感じで使われています!
以上です。最後まで読んでいただきありがとうございました。