Factoryパターン(2) - 引数にクラスを渡すFactory Method

Rubyによるデザインパターン』(ラス・オルセン著 ピアソン・エデュケーション刊)の例をPythonに変換して書いています。目次

Factory Methodでは、メソッドにクラスを引数として与える事が出来ます。


ところで、前回、池の生態系シミュレータを作りましたが、やはり池には藻や葦が生えてないとおかしいという事になり、「植物」に関する機能を追加する事にしました。

class Pond(object):
    def __init__(self, number_animals, number_plants):
        self.animals = []
        for i in xrange(number_animals):
            animal = self.new_animal("動物%d"%(i,))
            self.animals.append(animal)
        
        self.plants = []
        for i in xrange(number_plants):
            plant = self.new_plant("植物%d"%(i,))
            self.plants.append(plant)

class DuckWaterLilyPond(Pond):
    #ここにメソッドを定義

class FrogAlgaePond(Pond):
    #ここにメソッドを定義

このPondには問題があります。新種の動物・植物を追加するために、それを扱うPondのサブクラスがドンドン増えていく事です。

ここでPythonRubyも)の特長を利用します。それはクラスもオブジェクトであるという事です。つまり、クラスを変数に代入したり、引数に渡したり出来るのです。

class Pond(object):
    def __init__(self, number_animals, animal_class
                       number_plants, plant_class):
        self.animal_class = animal_class
        self.plant_class = plant_class
        
        self.animals = []
        for i in xrange(number_animals):
            animal = self.new_organism("animal", "動物%d"%(i,))
            self.animals.append(animal)
        
        self.plants = []
        for i in xrange(number_plants):
            plant = self.new_organism("plant", "植物%d"%(i,))
            self.plants.append(plant)
    
    def new_organism(self, type, name):
        if type == "plant":
            return self.plant_class(name)
        elif type == "animal":
            return self.animal_class(name)
        else:
            assert False, "wrong organism type %r"%(type,)


pond = Pond(10, Frog, 5, Algae)
pond.simulate_one_day()