initializeメソッドとattr_accessorについて

　初学者の私がRubyを学ぶ上でまず躓いたのがattr_accessorやinitializeメソッドだったので自分の中の整理の意味も含めて書いておきたいと思います。

attr_accessorを理解するためにはinitializeメソッドの理解が必要だと思うので先にそちらから書いていきます！因みに今回は例のポケモンを使って説明していきたいと思います。

## 目的
・ポケモン(Pokemon)というクラスを元に基本的な情報であるステータス（名前、体力、攻撃力、防御力）を持つリザードン(lizardon)を生み出す。（何でリザードン？かっこいいからにきm）

## 本編
### 1. クラス設定
まず、クラスの設定を行います。

```.rb

class Pokemon

end
```

まずはクラスの定義からですね。ここからリザードンに必要な情報を書いていきます。

### 2. ステータスの設定（セッターの定義）
　リザードンには名前（`name`）、体力（`hp`）、攻撃力（`offense`）、防御力（`defense`）の4つのステータスが存在しますので設定していきましょう。まず覚えるべき言葉が「セッター」です。セッターとは、簡単にいうと、ステータスの値を更新するためのメソッドです。


例えば、体力の更新するときは`lizardon.hp = 500`のように `=` を用いて値を代入します。そのため、メソッドを定義する際にも`hp =(hp)`の形で記述することになります。

```.rb
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`に格納されます。もう少し具体的にみていきます。

```.rb
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. ステータスの取得（ゲッターの定義）
　セッターでは、リザードンのステータスの設定ができました。が、これではまだ値をセットしただけにすぎません。折角セットした値ですがこれを取り出すことができないと意味ないですね。そこで今回はこの値をゲットするという意味での「ゲッター」を作っていきましょう！

```.rb
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
```
ゲッターを定義できたので、実際に取り出してみましょう。

```.rb
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
```

実行画面

```.rb
リザードン
78
84
78
```

ゲッターを利用して値を取り出すことができましたね！

### 4. initializeメソッド

　さて、いよいよ`initialize`メソッドについての説明です。ここまで理解できていたらそこまで難しくありません！`initialize`メソッドを簡単に説明すると、初期値の設定をするためのメソッドです。　

具体的には次のようにします。

```.rb

#初期値の設定
  def initialize
   @name = "リザードン"
   @hp = 78
   @offense = 84
   @defense = 78
  end
```

初期値の設定、これは実はさっきまでのコードで既に行っていました。該当の箇所はここです。

```.rb

# lizardonのステータスに値を設定
lizardon.name = "リザードン"
lizardon.hp = 78
lizardon.offense = 84
lizardon.defense = 78
```

なのでこちらの部分はカットして、それに伴うセッターもカットしてしまいましょう。


```.rb
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`演算子に引数を渡して値を設定します。

```.rb
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`に渡す引数もハッシュ形式で渡してあげましょう！
次のように書き換えられます。


```.rb
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）

　実はこれまでに書いてきたセッターやゲッターの処理はもっと簡潔に記述できます。それがアクセスメソッドです。

先ほどのコードを次のように直してみましょう。

```.rb
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
```

次のような結果になるはずです。

```.rb
リザードン
78
84
78
```

`attr_reader`はゲッターの役割を果たすことが理解できたかと思います。

### 7. アクセスメソッド（attr_writer）
これで一旦、リザードンの初期パラメーターは表現できました。しかし、もう少し一工夫しましょう。リザードンのHPは敵から受けるダメージによって変化する可能性がありますよね？そのためHPの初期値から値が変化するようにコードを書き直していきましょう。

```.rb
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）が再セットされます。

つまり最後の出力は次のようになるはずです。

```.rb

リザードンはダメージを受けた!　残りHPは48だ
```

この流れをもっと簡潔にするためのものが`attr_writer`です。

```.rb
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行で表すことができます。

```.rb
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
```

出力結果

``` .rb
リザードン
78
84
78
リザードンはダメージを受けた!　残りHPは48だ
```

##まとめ

`initialize`は初期化
`attr_reader`はゲッター
`attr_witer`はセッター
`attr_accessor`はセッターとゲッターの両方の機能

という感じで使われています！

以上です。最後まで読んでいただきありがとうございました。