空飛ぶとんジニア

平凡なエンジニアが日々関心を持ったことや学んだこと、感じたことを吐き出すブログ。緊張すると涙がでるのが特徴です。

【デザインパターン】RubyでStrategyパターン

この記事は『Head Firstデザインパターン』の内容を自分なりにメモしたものです。 サンプルコードをrubyで書き換えたりしているので、玄人の方はぜひコメントを!! 僕のように初級者で気になった方はぜひ書籍の方を確認してみてください^^

カモが飛ぶために必要なこと

最初に登場する構成(メソッドは見づらいので省略)

f:id:fiveislands:20160814111518j:plain

実際のコードはこんな感じ

class Duck
  def display
    raise "should implement display method."
  end
  def swim
    puts "I'm swimming."
  end
end

class MallardDuck < Duck
  def display
    puts "This is MallardDuck."
  end
end

実行コード

mallard_duck = MallardDuck.new
mallard_duck.display  #=> This is MallardDuck.
mallard_duck.swim     #=> I'm swimming.

ある時、マネージャーが言いました。
カモを飛べるようにしよう!
この場合、変更するのは簡単
Duckクラスにflyメソッドを追加しましょう!

class Duck
  ...
  def fly
    puts "I'm flying."
  end
end

問題の発生

しかし、先ほどの変更では問題があります。
Duckを継承している「ゴムのアヒル」までもが空を飛べるようになってしまいます。

どのように変更を行えばいいのでしょうか?

変わるもの、変わらないものを分離する

カモの振る舞いを分離します。

構成

f:id:fiveislands:20160814112519j:plain

実際のコードはこんな感じ

class Duck
  attr_accessor :fly_behavior

  def display
    raise 'should implement display method.'
  end
  def swim
    puts "i'm swimming."
  end
  def perform_fly
    @fly_behavior.fly
  end

end

class MallardDuck < Duck
  def initialize
    @fly_behavior = FlyWithWings.new
  end
  def display
    puts "this is mallard_duck."
  end
end

class FlyBehavior
  def fly
    raise 'should implement fly method.'
  end
end

class FlyWithWings < FlyBehavior
  def fly
    puts "I'm flying."
  end
end

class FlyNoWay < FlyBehavior
  def fly
    puts "I'm not flying."
  end
end

実行コードは

mallard_duck = MallardDuck.new
mallard_duck.display  #=> this is mallard_duck.
mallard_duck.perform_fly  #=> I'm flying.

これで、ゴムのアヒルが空を飛べてしまう問題は解決ですね。
コンストラクタでFlyNoWay.newを代入してやればいいです。
しかもこの設計のいいところは、システム側で振る舞いを変更できるようになることです。

こんな感じ

mallard_duck = MallardDuck.new
mallard_duck.display
mallard_duck.perform_fly  #=> I'm flying.
mallard_duck.fly_behavior = FlyNoWay.new
mallard_duck.perform_fly  #=> I'm not flying.

振る舞いの切り替えが行えています。

Strategyパターンの特徴

一連のアルゴリズム(今回の場合は振る舞い)を定義し、それぞれをカプセル化して交換可能にする。
Client(今回の場合はDuckクラス)とは独立してアルゴリズムを変更できる。

参考文献

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本