概要
- Strategy パターンとは
- 処理をほかのオブジェクトに移譲する
- 移譲されたオブジェクトを再利用できる
- 移譲されたオブジェクトそれぞれに共通のインターフェースを持たせることで、オブジェクトを交換して挙動を変えられる
例
- 鴨
- いろいろな種類の鴨がいる
- どれも「鳴く」メソッドを持っているが、種類によって鳴き声が違う
- そこで「鳴き方オブジェクト」を作って鴨に持たせる
- 「ガアガア」オブジェクト
- 「グエグエ」オブジェクト
- など
- 鴨の「鳴く」メソッドは実際には鳴き方オブジェクトの「鳴く」メソッドを呼び出すだけ
- 鳴き方オブジェクトを再代入することで、実行中に動的に鳴き方を変えることもできる
実装
- やや乱暴だが大体こんな感じ
- 鳴き方クラスの共通の親クラスを作り、親クラスの
quack()
は例外を返すようにすると実装漏れが防げる
- 鳴き方クラスの共通の親クラスを作り、親クラスの
# 鳴き方クラス(抽象風)
class Quack
def quack
raise
end
end
# 鳴き方クラス(具象風)
class Gaagaa < Quack
def quack
puts "gaagaa"
end
end
class Guegue < Quack
def quack
puts "guegue"
end
end
# 鴨
class Duck
attr_writer :voice
def perform_quack
@voice.quack
end
end
d = Duck.new
d.voice = Gaagaa.new
d.perform_quack # => gaagaa
d.voice = Guegue.new
d.perform_quack # => guegue
- 挙動を変えるという意味では、module を使ってもよいのでは?と思ったが、それだと挙動の動的変更ができない。
# 鳴き方モジュール
module Gaagaa
private
def quack
puts "gaagaa"
end
end
module Guegue
private
def quack
puts "guegue"
end
end
# 鴨
class Duck
include Guegue
def perform_quack
quack
end
end
d = Duck.new
d.perform_quack # => guegue
# gaagaa 鳴くように変更できない!