【Ruby】ややこしいゲッター/セッター/アクセッサーを解説【初心者向け】

本記事はこんな方向けです。

  • Rubyのゲッターやセッターが何か分からない人
  • attr_readerやattr_writerって何??の人
  • ついでにattr_accessorも分からない人
  • initializeが分からない人

Rubyの学習を始めた際に、『ゲッター』『セッター』が分からなくなる方もいるかと思います。

分かりにくい理由として、全ての参考書がゲッターとセッターの本来の形をすっ飛ばして説明していることが原因かなと思います。

本記事では「ゲッターやセッターの本来の姿」や「なぜ必要なのか?」を中心に解説していきます。

STEP1 ポケモンのキャラクターでセッターを理解しよう

まずはポケモンのキャラクターのステータスをRubyで表現していこうかと思います。

例えばピカチューは、『name(名前)』『hp(体力)』『offense(攻撃力)』『defense(防御力)』という属性を持っているとします。

この章では、ピカチュウに具体的なステータスを与えることを目的とします。

「ピカチューの攻撃力は30です。」のように、nameやhpには特定の文字や数字を入れてあげる必要があります。

そのためには、特定の文字や数字を入れてあげるメソッドを用意してあげます。コードで書くと下記のようになりますね。

class Pikachu
	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

メソッドを用意できたら、実際に値を設定していきます。

class Pikachu
	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

//インスタンスの作成
pikachu = Pikachu.new
//値を設定
pikachu.name = "ピカチュウ"
pikachu.hp = 100
pikachu.offense = 50
pikachu.defense = 30

これで、ピカチュウの名前や体力に値を設定できました。
このようにパラメーターを設定するメソッドを『セッター』と呼びます。

STEP2 セッターの表記を書きかえよう

前の章のコードでも『セッター』の役割を果たすのですが、実際はもう少し簡潔に書き直すことができます。

そこで登場するのが、「attr_writer」です。
先程のコードを書き直したのが、下記コードです。

class Pikachu
  attr_writer :name

  attr_writer :hp

  attr_writer :offense

  attr_writer :defense
end

pikachu = Pikachu.new
pikachu.name = "ピカチュウ"
pikachu.hp = 100
pikachu.offense = 50
pikachu.defense = 30

とてもシンプルになりましたね。

attr_writerと書くと、メソッドのように見えないので、一見何をしているのか分かりませんが、実はdef name=(name)のようなものを変換したものなのです。

上記コードは、もう少しまとめることができます。

class Pikachu
  attr_writer :name,:hp,:offense,:defense
end

pikachu = Pikachu.new
pikachu.name = "ピカチュウ"
pikachu.hp = 100
pikachu.offense = 50
pikachu.defense = 30

ここまでの話をまとめると…

あるパラメーターに値や文字を設定するためのメソッドが『セッター』で、『attr_writer』とシンプルに省略できる。

STEP3 ポケモンの初期値をinitializeで設定しよう

上記コードでは、ピカチュウが持つパラメータの初期値を下記のように設定していましたね。

class Pikachu
(省略)
end
pikachu = Pikachu.new
pikachu.name = "ピカチュウ"
pikachu.hp = 100
pikachu.offense = 50
pikachu.defense = 30

パラメータの初期値を設定するには、「initialize」を使うのが一般的です。

class Pikachu
	attr_writer :name,:hp,:offense,:defense
	def initialize
		@name = "ピカチュウ"
		@hp = 100
		@offense = 50
		@defense = 30
	end
end

pikachu = Pikachu.new

上記コードは書き方的に問題ないですが、初期値が固定になってしまいます

仮に「ピカチュウ1」と「ピカチュウ2」のように違うピカチュウがチームにいた場合、同じステータスになってしまいます….

これを防ぐにはinitializeメソッドに引数を与え、インスタンス作成時に具体的な文字や数字を与えてやればOKです。

class Pikachu
	attr_writer :name,:hp,:offense,:defense
	def initialize(name,hp,offense,defense)
		@name = name
		@hp = hp
		@offense = offense
		@defense = defense
	end
end

pikachu_1 = Pikachu.new("ピカチュウ1",100,50,30)
pikachu_2 = Pikachu.new("ピカチュウ2",40,20,10)

initializeメソッドでパラメータの初期値を設定できる。

STEP4 ポケモンのキャラクターでゲッターを理解しよう

ゲッターでピカチュウの攻撃力などを設定できました。

次にやりたいことは、設定したパラメーターを呼び出すことです。
実際のゲームを想像してもらえると分かりやすいかと思います。

『ピカチュウの攻撃力は30です。』

『ピカチュウが攻撃した。』

などのメッセージが表示されますよね??

しかし今の状態では、パラメータの設定しかできず、パラメータの中身を呼び出せません。

『???の攻撃力は???です。』

『???が攻撃した。』

そこで登場するのが、『ゲッター』です。
実際にコードを書いてみましょう。

class Pikachu
  attr_writer :name,:hp,:offense,:defense
  //以下ゲッターの定義
  def name
    @name
  end
  def hp
    @hp
  end  
  def offense
    @offense
  end  
  def defense
    @defense
  end
	def initialize(name,hp,offense,defense)
		@name = name
		@hp = hp
		@offense = offense
		@defense = defense
	end
end

pikachu = Pikachu.new("ピカチュウ",100,50,30)

ゲッターもメソッドなので、pikachuというインスタンスに対して、pikachu.nameとすると設定しておいた「ピカチュウ」を呼び出せます。

セッター同様、ゲッターも下記のように省略できます。

class Pikachu
  attr_writer :name,:hp,:offense,:defense
  attr_reader :name,:hp,:offense,:defense
	def initialize(name,hp,offense,defense)
		@name = name
		@hp = hp
		@offense = offense
		@defense = defense
	end
end

pikachu = Pikachu.new("ピカチュウ",100,50,30)

#パラメータの呼び出し
puts pikachu.name 
#ピカチュウ
puts pikachu.hp
#100
puts pikachu.offense
#50
puts pikachu.defense
#30

ゲッターを設定することで、インスタンスの名前や体力を呼び出すことができるようになりました。


ゲッターとセッターの表記は『attr_accessor』を使えば、簡潔に書けます。

class Pikachu
  attr_accessor :name,:hp,:offense,:defense
	def initialize(name,hp,offense,defense)
		@name = name
		@hp = hp
		@offense = offense
		@defense = defense
	end
end

pikachu = Pikachu.new("ピカチュウ",100,50,30)

#パラメータの呼び出し
puts pikachu.name 
#ピカチュウ
puts pikachu.hp
#100
puts pikachu.offense
#50
puts pikachu.defense
#30

ゲッターはパラメータを外部から呼び出すためのもの。

補足:ゲッターの設定は注意深くしよう!

ちなみに上記コードでは、全てのパラメータを書き換え可能に設定していますが、これは実際のゲームだとバグを生み出し放題ですね。

なぜなら….

セッターに設定したパラメーターはクラスの外部から書き換え可能だから。

例えば、下記コードのようにパラメータを外部から書き換えた場合どうなるでしょうか。

犬

外部からパラメータを書き換えて、ピカチューをカイリキーにしてやらあ!!

class Pikachu
  attr_writer :name,:hp,:offense,:defense
  attr_reader :name,:hp,:offense,:defense
	def initialize(name,hp,offense,defense)
		@name = name
		@hp = hp
		@offense = offense
		@defense = defense
	end
end

pikachu = Pikachu.new("ピカチュウ",100,50,30)

# パラメータを確認
puts pikachu.name
puts pikachu.hp
puts pikachu.offense
puts pikachu.defense

# 実行結果
# ピカチュウ
# 100
# 50
# 30

# パラメータを書き換え
pikachu.name = "カイリキー"
pikachu.hp = 300
pikachu.offense = 500
pikachu.defense = 200

# 再度パラメータを確認
puts pikachu.name
puts pikachu.hp
puts pikachu.offense
puts pikachu.defense

# 実行結果
# カイリキー
# 300
# 500
# 200

はい、ピカチューがカイリキーに進化してしまいました。

このようにセッターでパラメータを設定することで、本来書き換えてはいけない情報も書き換えられる可能性があるので注意です。

ゲッターもセッターも単なるメソッドだよと分かれば、扱いやすくなるのではと思います。