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

Rubyによるデザインパターン

Rubyによるデザインパターン

利用する場面

あるオブジェクトについて、ある場合にはa,b,cというクラスを利用したく、別の場合にはx,y,zというクラスを利用したい場合。

あれこれ

  • factoryパターンとは、template methodパターンをクラスの選択(及びインスタンスの生成)に関して適用した場合の呼び名。
    • すなわち、サブクラスを用意してサブクラスの中でそれぞれ適切なクラスを選択して利用する。
  • abstract factoryパターンとは、strategyパターンをクラスの選択(及びインスタンスの生成)に関して適用した場合の呼び名。

サンプル

factoryパターンから。

class Dinner
  attr_reader :food, :drink
  def initialize
    new_food
    new_drink
  end
end

class Sushi ; end
class Steak ; end
class Sake  ; end
class Wine  ; end

class JapaneseDinner < Dinner
  def new_food
    @food = Sushi.new
  end

  def new_drink
    @drink = Sake.new
  end
end

class WesternDinner < Dinner
  def new_food
    @food = Steak.new
  end

  def new_drink
    @drink = Wine.new
  end
end

j = JapaneseDinner.new
p j.food   # => #<Sushi:0x007fee07832438>
p j.drink  # => #<Sake:0x007fee07832410>

w = WesternDinner.new
p w.food   # => #<Steak:0x007fee07831e98>
p w.drink  # => #<Wine:0x007fee07831e70>

続いてabstract factoryパターン。

class Dinner
  attr_reader :food, :drink

  def initialize(dish_factory)
    @dish_factory = dish_factory
    @food = @dish_factory.new_food
    @drink = @dish_factory.new_drink
  end
end

class Sushi ; end
class Steak ; end
class Sake  ; end
class Wine  ; end

class JapaneseDishFactory
  def new_food
    Sushi.new
  end

  def new_drink
    Sake.new
  end
end

class WesternDishFactory
  def new_food
    Steak.new
  end

  def new_drink
    Wine.new
  end
end

j = Dinner.new(JapaneseDishFactory.new)
p j.food   # => #<Sushi:0x007fc075078e00>
p j.drink  # => #<Sake:0x007fc075078dd8>

w = Dinner.new(WesternDishFactory.new)
p w.food   # => #<Steak:0x007fc0750789c8>
p w.drink  # => #<Wine:0x007fc0750787e8>

個々のabstract factoryをクラスにせず、インスタンスにしてもよい。

class Dinner
  attr_reader :food, :drink

  def initialize(dish_factory)
    @dish_factory = dish_factory
    @food = @dish_factory.new_food
    @drink = @dish_factory.new_drink
  end
end

class Sushi ; end
class Steak ; end
class Sake  ; end
class Wine  ; end

class DishFactory
  def initialize(food, drink)
    @food = food
    @drink = drink
  end

  def new_food
    @food.new
  end

  def new_drink
    @drink.new
  end
end

japanese_dish_factory = DishFactory.new(Sushi, Sake)
j = Dinner.new(japanese_dish_factory)
p j.food   # => #<Sushi:0x007fc075078e00>
p j.drink  # => #<Sake:0x007fc075078dd8>

western_dish_factory = DishFactory.new(Steak, Wine)
w = Dinner.new(western_dish_factory)
p w.food   # => #<Steak:0x007fc0750789c8>
p w.drink  # => #<Wine:0x007fc0750787e8>