Factoryパターン(1) - Factory Method
『Rubyによるデザインパターン』(ラス・オルセン著 ピアソン・エデュケーション刊)の例をPythonに変換して書いています。目次
- Factoryパターン(1) - Factory Method
- Factoryパターン(2) - 引数にクラスを渡すFactory Method
- Factoryパターン(3) - Abstract Factory
- Factoryパターン(4) - 引数にクラスを渡すAbstract Factory
どのクラスを選択するかは、時に難しい問題になります。いや、もちろん、dictとsetとstringを選ぶのは簡単だと思いますが・・・。
Template Methodパターンで作った、複数のクラスのどれを使うのかは、時に重要な問題です。クラスの選択をパッケージ化するのがFactoryパターンです。
池の生態系シミュレータを作りました。
Pond(池)には、Duck(アヒル)が住んでいて、アヒルは食べたり鳴いたり眠ったりします。
class Pond(object): def __init__(self, number_ducks): self.ducks = [] for i in xrange(number_ducks): self.ducks.append(Duck("アヒル%d"%(i,))) #ここで「Duck」を作っている def simulate_one_day(self): for duck in self.ducks: duck.eat() duck.speak() duck.sleep() class Duck(object): def __init__(self, name): self.name = name def eat(self): print("アヒル(%s)は食事をしています。"%(self.name,)) def speak(self): print("アヒル(%s)はガーガー鳴いています。"%(self.name,)) def sleep(self): print("アヒル(%s)は寝ています。"%(self.name,))
このシミュレータは大変上手くいったので、
Frog(カエル)にも対応しようという事になりました。
しかし、上のコードでは明示的にアヒルを生成しているという問題があります。
そこで、Template Methodパターンを活用しましょう!
class Pond(object): def __init__(self, number_animals): self.animals = [] for i in xrange(number_animals): animal = self.new_animal("動物%d"%(i,)) self.animals.append(animal) def simulate_one_day(self): for animal in self.animals: animal.eat() animal.speak() animal.sleep() def new_animal(self, name): raise NotImplementedError class FrogPond(Pond): """カエルだらけの池""" def new_animal(self, name): return Frog(name) class DuckPond(Pond): """アヒルだらけの池""" def new_animal(self, name): return Duck(name)
これをFactory Methodパターンと呼びます。
つまり、Factory MethodはTemplate Method の一変種です。
Factory Methodパターンにおいて、PondのようなクラスをCreator、DuckPond、FrogPondのようなクラスをConcrete Creator と呼びます。
ちなみに、共通のインターフェイスを持たなければならないのは、Pondの側だけではなく、カエルやアヒルの方もそうであることに注意です。