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

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

パラメータ化された Factory Method パターン

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 WaterLity
  def initialize(name)
    @name = name
  end

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

class Pond
  def initialize(number_animals, number_plants)
    @animals = []
    number_animals.times do |i|
      animal = new_organism(:animal, "動物#{i}")
      @animals << animal
    end

    @plants = []
    number_plants.times do |i|
      plant = new_organism(: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

class DuckWaterLilyPond < Pond
  def new_organism(type, name)
    if type == :animal
      Duck.new(name)
    elsif type == :plant
      WaterLily.new(name)
    else
      raise "Unknown"
    end
  end
end

class FrogAlgaePond < Pond
  def new_organism(type, name)
    if type == :animal
      Frog.new(name)
    elsif type == :plant
      Algae.new(name)
    else
      raise "Unknown"
    end
  end
end

pond = FrogAlgaePond.new(3, 2)
pond.simulate_one_day

具象クラスも外から渡すパターン

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 Pond
  def initialize(number_animals, animal_class,
                 number_plants, plant_class)
    @animal_class = animal_class
    @plant_class = plant_class

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

    @plants = []
    number_plants.times do |i|
      plant = new_organism(: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

  def new_organism(type, name)
    if type == :animal
      @animal_class.new(name)
    elsif type == :plant
      @plant_class.new(name)
    else
      raise "Unknown"
    end
  end
end


pond = Pond.new(3, Duck, 2, WaterLily)
pond.simulate_one_day

animals と plants の組み合わせを呼び出し元から決めることができます。

この組み合わせも構造化するのは次の part2 で実施してみます。