最近コードを書いている時にDRYなコードを書くのには親クラスを作って継承させるべきなのかModuleでMixinするべきなのか、どっちが良いのか整理して考えてみた。
最初にお断りをしておくと、多分どちらでも問題ないと思うし、好みの問題だと思います。
##ある高校の先生を例に考えてみる。
class Teacher
def prepare_lesson
#授業の予習をする
@naiyou = "教科書を読んでくる"
end
def lesson
#授業をする
@naiyou.show
end
def create_test
#英語のテストを作成
@test = "先生が考えてくる"
end
def examine
#テストを実行する
@test.exec
end
def check_test
#テストを採点
@test.check
end
etc...
end
先生のやる事は挙げればきりがないが例えば上記のような事をすると考えよう。
でも先生は1人で数学や英語、化学や国語を教えたりするスーパーマンではない。もしそんなスーパーマンがいたらコードの中身はきっとifやcaseで埋め尽くされてしまう。
##どうしようか・・・ 継承 or Mixin
そうならないように役割をもう少し分けて共通項はDRYにした方がいいよねと思い立った故に、あれ継承?Mixin?
授業の予習や、テストを作るといった事は教科によって内容が変わるのでそれぞれの専門のクラスに持たせるとするが授業をしたりテストを実施するのは教科の内容にかかわらず鐘がなってから終わるまで準備してきたもの生徒たちに提供するだけなので親クラスやモジュールにまとめることにする。
class Teacher
def lesson
@naiyou.show
end
def examine
@text.exec
end
end
class Teacher::MathTeacher < Teacher
def prepare_lesson
#数学の授業の予習をする
@naiyou = "数学の問題をといてくる"
end
def create_test
#数学のテストを作成
@test = "数学の教科書から作る"
end
end
class Teacher::EnglishTeacher < Teacher
def prepare_lesson
#英語の授業の予習をする
@naiyou = "英語の教科書を読んでくる"
end
def create_test
#英語のテストを作成
@test = "英語の教科書から作る"
end
end
module Teacher
def lesson
@naiyou.show
end
def examine
@test.exec
end
end
class Teacher::MathTeacher
include Teacher
def prepare_lesson
#数学の授業の予習をする
@naiyou = "数学の問題をといてくる"
end
def create_test
#数学のテストを作成
@test = "数学の教科書から作る"
end
end
class Teacher::EnglishTeacher
include Teacher
def prepare_lesson
#英語の授業の予習をする
@naiyou = "英語の教科書を読んでくる"
end
def create_test
#英語のテストを作成
@test = "英語の教科書から作る"
end
end
上は継承 下はMixin
この状態であれば、結論付けられないので他のクラスを登場させてみる。
##生徒クラス登場
class Student
def take_lessons
#授業を受ける
end
def move_to_a gymnasium
#体育館に移動する
end
end
ここで生徒クラスを登場させてみる。生徒は教師と大きく関わりを持つが教師がやるべきことと生徒がやるべきことは同じじゃない。 そん中でも教師と生徒が同じ動作をすることはある。例えば全校集会の為に体育館に移動するとか。 生徒クラスにも教師クラスにも体育館に移動するメソッドは全く同じであるが、2つを内包するような上位概念があるだろうか? schoolクラスを作る? schoolクラスからインスタンス化されたオブジェクトはそれ単体でも実行できる。 学校というオブジェクトが体育館に移動するという主語になるかと言われると気持ちが悪くて想像したくない。
class School
def move_to_a_gymnasium
#体育館に移動する
end
end
class Teacher < School
...#その他
end
class Student < School
...#その他
end
Teacher.new.move_to_a_gymnasium
Student.new.move_to_a_gymnasium
School.new.move_to_a_gymnasium !?!?!?!?
そこで、こんな時こそ微妙な距離感の2つのクラスの間にはModuleでMixinするというのがあっているのではないかと思いました。ということで全校集会は学校のイベントなのでSchoolEventモジュールを用意
module SchoolEvent
def move_to_a_gymnasium
#体育館に移動する
end
end
class Teacher
include SchoolEvent
...#その他
end
class Student
include SchoolEvent
...#その他
end
Teacher.new.move_to_a_gymnasium
Student.new.move_to_a_gymnasium
##結論
プレフィックスを持つようなグループに分けられるようなクラスをDRYにする時は親クラスを用いて、汎用的な共通の処理が必要な場合はModule化してMixinを使ってあげるというのが良いかなと思いました。