GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。
■ Factory Method(ファクトリメソッド)
Factory Method パターン(ファクトリメソッド・パターン)とは、GoF (Gang of Four; 四人組)によって定義されたデザインパターンの1つである。 Factory Method パターンは、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換えることで、 アプリケーションに特化したオブジェクトの生成をサブクラスに追い出し、クラスの再利用性を高めることを目的とする。
Virtual Constructor パターンとも呼ばれる。
UML class diagram
□ 備忘録
振る舞いに関するTemplate Method
パターンは、スーパークラスで処理の大枠を作って、サブクラスで具体的処理を決定するというもの。このTemplate Method
パターンを、インスタンスをつくる場面に適用したものが、Factory Method
パターンらしい。
■ "Factory Method"のサンプルプログラム
Factory Methodパターンは、以下の特徴があるようです。
- インスタンスの作り方をスーパークラス側で定める
- 具体的なクラス名までは定めない
- 具体的な肉付けは、全てサブクラス側で行う
これによって、インスタンス作成のための枠組み(フレームワーク)と実際のインスタンス作成のクラスを分けて考えることができるようになるそうです。
実際に、Factory Methodパターンを使って、「身分証明書カード(IDカード)を作る工場」を題材としたサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。
-
Hiroshi Yuki"
,Tomura
,Hanako Sato
の3名の身分証明書カードを作成する -
Hiroshi Yuki"
,Tomura
,Hanako Sato
の3名の身分証明書カードを使用する
$ python Main.py
I'll create Hiroshi Yuki's card
I'll create Tomura's card
I'll create Hanako Sato's card
I'll use Hiroshi Yuki's card
I'll use Tomura's card
I'll use Hanako Sato's card
サンプルプログラムを動かしただけだと、いまいち、何がしたいのかよく分かりませんね
つづいて、サンプルプログラムの詳細を確認していきます。
■ サンプルプログラムの詳細
Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/FactoryMethod
- ディレクトリ構成
.
├── Main.py
└── framework
├── __init__.py
├── factory.py
└── idcardfactory
├── __init__.py
└── id_card_factory.py
(1) Product(製品)の役
Product
役では、インスタンスが持つべきインタフェースを定めます。
サンプルプログラムでは、Product
クラスが、この役を努めます。
from abc import ABCMeta, abstractmethod
... (snip)
class Product(metaclass=ABCMeta):
@abstractmethod
def use(self):
pass
(2) Creator(作成者)の役
Creator
役では、Product
を生成する役割を担います。実際に生成するConcreteProduct
役については何も知りません。
さらに、Creator
役には、インスタンスの各部分を作るためのメソッドが用意されます。
サンプルプログラムでは、Factory
クラスが、この役を努めます。
from abc import ABCMeta, abstractmethod
class Factory(metaclass=ABCMeta):
def create(self, owner):
p = self.createProduct(owner)
self.registerProduct(p)
return p
@abstractmethod
def createProduct(self, owner):
pass
@abstractmethod
def registerProduct(self, product):
pass
... (snip)
(3) ConcreteProduct(具体的製品)の役
ConcreteProduct
役は、Product
役のインタフェースを実装しているクラスです。実際のインスタンス作成後に呼び出されるメソッドが、ここで定義されます。
サンプルプログラムでは、IDCardProduct
クラスが、この役を努めます。
from framework.factory import Factory, Product
... (snip)
class IDCardProduct(Product):
def __init__(self, owner):
self.owner = owner
print("I'll create {0}'s card".format(self.owner))
def use(self):
print("I'll use {0}'s card".format(self.owner))
(4) ConcreteCreator(具体的作成者)の役
ConcreteCreator
役は、Creator
役のインタフェースを実装しているクラスです。具体的な製品を作るクラスを定めます。
サンプルプログラムでは、IDCardFactory
クラスが、この役を努めます。
from framework.factory import Factory, Product
class IDCardFactory(Factory):
def __init__(self):
self.owners = []
def createProduct(self, owner):
return IDCardProduct(owner)
def registerProduct(self, product):
self.owners.append(product.owner)
... (snip)
(5) Client(依頼人)の役
サンプルプログラムでは、startMain
メソッドが、この役を努めます。
from framework.idcardfactory.id_card_factory import IDCardFactory
def startMain(factoryObject):
card1 = factoryObject.create("Hiroshi Yuki")
card2 = factoryObject.create("Tomura")
card3 = factoryObject.create("Hanako Sato")
card1.use()
card2.use()
card3.use()
if __name__ == "__main__":
startMain(IDCardFactory())