フィヨルドブートキャンプでメンターとしてコードレビューをしています。自由な形式でプログラムを書く課題の場合、やはりオブジェクト指向プログラミングにみなさん苦戦しているようです。
特に、オブジェクト指向プログラミングのイメージが掴めないと、
「何をクラスメソッドにして何をインスタンスメソッドにすればいいのか」
がわかりません。(みんなここで詰まっている)
なので、これを説明するのはものすごく難しいんですが、挑戦してみます。
(クラスを定義する記法や使い方はRuby超入門などで読んだという方を前提とします。)
クラスとインスタンス
クラス と インスタンス は 鋳型 と 実体 だと考えてください。
鋳型とはこういうやつです。
タイヤキの鋳型はタイヤキそのものとは別のものですが、その鋳型からできる全てのタイヤキの形を決めています。
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
実際は実装上の都合やテクニックが加わってくるのでこれに当てはまらない場合もありますがあくまで基本の考え方はこれです。