第13章 正しいクラスを選び出す: Factory part2
Ruby
Published: 2019-06-30

「Rubyによるデザインパターン」の読書メモです。

Abstract Factory

Factory Method パターンがTemplate Method パターンをオブジェクトの作成に適用したのと同じように、Abstract Factory パターンは同じ問題にStrategyパターンを適用したのです。

アブストラクトファクトリで大事なことは、どの製品の型が一緒になるのかという知識をカプセル化することなのです。

class Duck
  def initialize(name)
    @name = name
  end

  def eat
    puts "アヒル #{@name} は食事中です。"
  end

  def speak
    puts "アヒル #{@name} はガーガー鳴いています。"
  end

  def sleep
    puts "アヒル #{@name} は静かに眠っています。"
  end
end

class Frog
  def initialize(name)
    @name = name
  end

  def eat
    puts "カエル #{@name} は食事中です。"
  end

  def speak
    puts "カエル #{@name} はゲロゲロっと鳴いています。"
  end

  def sleep
    puts "カエル #{@name} は眠りません。一晩中ゲロゲロ鳴いています。"
  end
end

class Algae
  def initialize(name)
    @name = name
  end

  def grow
    p "藻 #{@name} は日光を浴びて育ちます。"
  end
end

class WaterLily
  def initialize(name)
    @name = name
  end

  def grow
    p "睡蓮 #{@name} は浮きながら日光を浴びて育ちます。"
  end
end

class Tree
  def initialize(name)
    @name = name
  end

  def grow
    p "樹木 #{@name} が高く育っています。"
  end
end

class Tiger
  def initialize(name)
    @name = name
  end

  def eat
    puts "トラ #{@name} は食べたいものを何でも食べます。"
  end

  def speak
    puts "トラ #{@name} はガオーとほえています。"
  end

  def sleep
    puts "トラ #{@name} は眠くなったら眠ります。"
  end
end

class PondOrganismFactory
  def new_animal(name)
    Frog.new(name)
  end

  def new_plant(name)
    Algae.new(name)
  end
end

class JungleOrganismFactory
  def new_animal(name)
    Tiger.new(name)
  end

  def new_plant(name)
    Tree.new(name)
  end
end

class Habitat
  def initialize(number_animals, number_plants, organism_factory)
    @organism_factory = organism_factory

    @animals = []
    number_animals.times do |i|
      animal = @organism_factory.new_animal("動物#{i}")
      @animals << animal
    end

    @plants = []
    number_plants.times do |i|
      plant = @organism_factory.new_plant("植物#{i}")
      @plants << plant
    end
  end

  def simulate_one_day
    @plants.each {|plant| plant.grow}
    @animals.each {|animal| animal.speak}
    @animals.each {|animal| animal.eat}
    @animals.each {|animal| animal.sleep}
  end
end

jungle = Habitat.new(1, 4, JungleOrganismFactory.new)
jungle.simulate_one_day

pond = Habitat.new(2, 4, PondOrganismFactory.new)
pond.simulate_one_day

Factory の一段上のレイヤーで、組み合わせを担っています。

まとめ

「どのクラスを選ぶのか?」という問いに答えるための技術です。