定义:把使用哪个类的决定放在子类的技巧成为工厂方法模式

元素:在工厂方法模式中有两个元素,第一个元素是创造者,第二个元素是产品,其中创造者有父类和以及继承父类的子类组成,由子类决定生产哪个生产者对象。在下面的uml中,factory是生产者,product是产品。

本质:工厂方法模式的核心是模板方法模式在创建对象问题上的应用。

uml:

#代码简化演示
class Duck
  def eat
    puts "duck is eating"
  end
end

class Frog
  def eat
    puts "frog is eating"
  end
end

class Pond
  def initialize
    @pond = new_animal
  end

  def simulate
    @pond.eat
  end
end

class DuckPond < Pond
  def new_animal
    Duck.new
  end
end

class FrogPond < Pond
  def new_animal
    Frog.new
  end
end

duck_pond = DuckPond.new
duck_pond.simulate

上述代码分析:上面的代码中Pond是生产者,该生产者是基类,该基类定义了生成对象的抽象方法,它有两个子类,使用两个子类来具体决定产生那个类对象。

上面的代码是仅仅只有动物一种类型的情况下,如果随着代码增加,需要增加植物等其他类型,需要新建一个new plant方法,随着类型的增多的类似new plant方法,为了免除增加方法的烦恼,下面使用一次性的new organism来替代new plant和new animal

#增加new_organism来替代new_animal

class Duck
  def eat
    puts "duck eat"
  end
end

class Frog
  def eat
    puts "frog eat"
  end
end

class WaterLily
  def grow
    puts "waterlily grow"
  end
end

class Algae
  def grow
    puts "algae grow"
  end
end

class Pond
  def initialize
    @animal = new_organism(:animal)
    @plant = new_organism(:plant)
  end

  def simulate
    @animal.eat
    @plant.grow
  end
end

class DuckWaterLilyPond < Pond
  def new_organism(type)
    if type == :animal
      Duck.new
    elsif type == :plant
      WaterLily.new
    else
      raise "unknown organism type #{type}"
    end
  end
end

class FrogAlgaePond < Pond
  def new_organism(type)
    if type == :animal
      Frog.new
    elsif type == :plant
      Algae.new
    else
      raise "unknown organism type #{type}"
    end
  end
end

one = DuckWaterLilyPond.new
one.simulate

two = FrogAlgaePond.new
two.simulate

上面代码的问题是需要为了生成一些类型必须写很多子类,比如DuckWaterLilyPond和FrogAlgaePond,可以通过将Frog, Duck, WaterLily, Algae放置到变量中来消除子类的继承,其实这些类也只是对象,作用是用来产生其他对象的对象。

#消除子类
class Duck
  def eat
    puts "duck eat"
  end
end

class Frog
  def eat
    puts "frog eat"
  end
end

class WaterLily
  def grow
    puts "waterlily grow"
  end
end

class Algae
  def grow
    puts "algae grow"
  end
end

class Pond
  def initialize(animal_class, plant_class)
    @animal_class = animal_class
    @plant_class = plant_class
    @animal = new_organism(:animal)
    @plant = new_organism(:plant)
  end

  def simulate
    @animal.eat
    @plant.grow
  end

  def new_organism(type)
    if type == :animal
      @animal_class.new
    elsif type == :plant
      @plant_class.new
    else
      raise "unknown organism type #{type}"
    end
  end
end

one = Pond.new(Duck, WaterLily)
one.simulate

results matching ""

    No results matching ""