読者です 読者をやめる 読者になる 読者になる

「オブジェクト指向設計実践ガイド」を読んだ

読書録 Ruby

Practical Object-Oriented Design in Ruby: An Agile Primer (Addison-Wesley Professional Ruby)

Practical Object-Oriented Design in Ruby: An Agile Primer (Addison-Wesley Professional Ruby)

以前英語版をkindleで買ったものの案の定読まず、日本語版が出版されたと聴いて早速買って読んでみた。

読んでて思ったのは結局のところオブジェクト指向で最も重要な概念はメッセージパッシングではなかろうかということ。

つまりオブジェクト指向がでてくる以前は関数名が競合する恐れを考慮して以下のように書く必要があった。(例はrubyですが。。。)

def getWidthFromHoge(a, b, c)
  # 引数の状態によって場合分け
  if a == piyo
    ...
  end
end

def getWidthFromHuga(a, b, c)
  # 引数の状態によって場合分け
  if a == piyo
    ...
  end
end

getWidthFromHoge(a, b, c)
getWidthFromHuga(a, b, c)

「引数の値がこうだったらこう」みたいに状態を元に条件分岐を書いてあげなければならない。 だから変更の影響範囲が大きく、例えば誰かが引数に入れる変数の状態を変更した際にバグるみたいなことが容易に起こりうる。

しかしオブジェクト指向以後は関数をオブジェクトに紐づくメソッドという形で定義できるようになったため以下のように簡潔にかける。 (以下適当な例)

class Hoge
  attr_reader :a, :b, :c
  def initialize(a, b, c)
    @a = a
    @b = b
    @c = c
  end

  def width
    a.piyo
  end
end

class Huga
  attr_reader :a, :b, :c
  def initialize(a, b, c)
    @a = a
    @b = b
    @c = c
  end

  def width
    a.piyo
  end
end

hoge = Hoge.new
huga = Huga.new
hoge.width
huga.width

つまりメソッドという形でオブジェクトに対してwidthというメッセージを送り、各オブジェクトがそれに応答できればよいのだ。(ダックタイピング)

またこれはメソッド内の引数に対する送信メッセージでも同じで、クラスは「引数aが何であるか」など知らなくてよく引数aはただメソッドpiyoというメッセージに応答できればよい。

もしここでダックタイピングできなければ以下のようになる。

def width
  case a
  when Foo
    # 何らかの処理
  when Bar
    # 何らかの処理
  else
  end
end

もし、aがBazクラスでありうる可能性があればcaseにBazも加えなければならない。このように依存度が高くなれば変更のコストが高まり、あちらを動かせばこちらも動く状態になってしまう。

またこのダックタイピングによって達成されたポリモーフィズムは継承やmixinなどでも達成することができ、これらはオブジェクトに対する一つのメッセージが多くの形態を持つための手段でしかない。 だからオブジェクト指向 == 継承みたいなのは間違い。

とまあごちゃごちゃメモがてら書いてみました。 全体としては容易に書かれていて理解しやすく、良い本でした。