フィヨルドブートキャンプでメンターとしてコードレビューをしています。自由な形式でプログラムを書く課題の場合、やはりオブジェクト指向プログラミングにみなさん苦戦しているようです。

特に、オブジェクト指向プログラミングのイメージが掴めないと、

「何をクラスメソッドにして何をインスタンスメソッドにすればいいのか」

がわかりません。(みんなここで詰まっている)

なので、これを説明するのはものすごく難しいんですが、挑戦してみます。

(クラスを定義する記法や使い方はRuby超入門などで読んだという方を前提とします。)

クラスとインスタンス

クラスインスタンス鋳型実体 だと考えてください。

鋳型とはこういうやつです。

Image from Gyazo

タイヤキの鋳型はタイヤキそのものとは別のものですが、その鋳型からできる全てのタイヤキの形を決めています。

Image from Gyazo

Person(人)クラスで考えてみます。

Person(人)というものは現実の世界にはいません。実際にいるのは駒形、町田といった人の実体です。哺乳類という動物がいないのと同じです。実際にいるのはポチやタマです。

Personにはname(名前)やage(年齢)といった属性がありますが、「そういう属性があるよ」ということは共通していますが、実際の名前はそれぞれ実体によって違います。

クラス変数とインスタンス変数

そうやって考えてみると、変数に関してはクラス変数(もしくは定数)とインスタンス変数のどちらにすべきか自然とわかると思います。

例えば「目の数」という属性はPersonに共通する内容なのでクラス変数(もしくは定数)がふさわしいです。「性別」という属性はインスタンスによって違うのでインスタンス変数がふさわしいです。

クラスメソッドとインスタンスメソッド

全てをクラス変数とクラスメソッドで処理するというのは手続き型プログラミングの世界です。

関数(メソッド)は極力引数の情報だけで処理が完結すべきというのは関数型プログラミングの世界です。

オブジェクト指向プログラミングでは、極力「インスタンス変数を使ってそのインスタンス自身に処理させる」というのが基本です。

例えばself_introduce(自己紹介する)というメソッドを作る場合、それぞれこうなります。

手続き型プログラミング:

class Person
  def self.name=(name)
    @@name = name
  end

  def self.self_introduce
    puts "I'm #{@@name}."
  end
end

Person.name = "komagata"
Person.self_introcude

関数型プログラミング:

def self_introduce(name)
  puts "I'm #{name}."
end

self_introduce("komagata")

オブジェクト指向プログラミング:

class Person
  def initialize(name)
    @name = name
  end

  def self_introcude
    puts "I'm #{name}."
  end
end

komagata = Person.new("komagata")
komagata.self_introduce

どれが良い悪いというのはないですが、オブジェクト指向プログラミングは最後のスタイルです。

極力、実体(インスタンス)が個別に持つ情報を利用してインスタンスメソッドを呼び出して処理する。そういう書き方が基本です。

例えば「人を探す」というメソッドがあった場合、(なんらかの人物が他の人物を探すとかでない限り)特定の実体には関係がないのでクラスメソッドが適しています。

class Person
  def self.find(name)
    # 探して新しいPersonインスタンスを返す
  end
end

実際は実装上の都合やテクニックが加わってくるのでこれに当てはまらない場合もありますがあくまで基本の考え方はこれです。