Rubyによるデザインパターンまとめ : adapter

利用する場面

やりとりをさせたい複数のオブジェクトの間でインターフェースが噛み合わないとき。 一方または両方のクラスのインターフェースを変更してもよいが、インターフェースを揃える役割をadapterに担わせて解決することができる。

その他

  • 呼び出される側をいじることに注意する。
  • 永続的にorその場限りで必要なメソッドをもたせてもよいのでは?と思ったら、まさしくその説明がでてきた。
  • つまり、クラスの上書きor特異メソッド。
  • 「アダプタではいくらかの複雑さと引き換えにカプセル化を守ることができます。クラスの変更ではいくらかの単純化と引き換えに、内部をいじくり回すコストがかかります。」

サンプル

犬は人間の挨拶に答えられないが、adapterを使って答えられるようにしてみる。

class Creature
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Man < Creature
  def greet(man)
    p "hello, #{man.name}"
    man.reply(self)
  end

  def reply(man)
    p "hello, #{man.name}"
  end
end

class Dog < Creature
  def bark
    p "bowwow"
  end
end

taro  = Man.new(:taro )
jiro  = Man.new(:jiro )
pochi = Dog.new(:pochi)

taro.greet(jiro) # => "hello, jiro", "hello, taro"
taro.greet(pochi) # => "hello, pochi", (NoMethodError)

class DogAdapter
  attr_reader :name

  def initialize(dog)
    @dog = dog
    @name = dog.name
  end
    
  def reply(man)
    p "hello, #{man.name}"
  end
end

speakable_pochi = DogAdapter.new(pochi)
taro.greet(speakable_pochi) # => "hello, pochi", "hello, taro"

特異メソッドを使って、ポチだけが話せるようにしてみる。

class << pochi
  def reply(man)
    p "hello, #{man.name}"
  end
end

taro.greet(pochi) # => "hello, pochi", "hello, taro"

ちなみに特異メソッドは以下の書き方でも定義できる。

def pochi.reply(man)
  p "hello, #{man.name}"
end

taro.greet(pochi) # => "hello, pochi", "hello, taro"