Pythonで、デザインパターン「Factory Method」を学ぶ

GoFのデザインパターンを学習する素材として、書籍「[増補改訂版Java言語で学ぶデザインパターン入門](https://www.hyuki.com/dp/)」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。

# ■ Factory Method（ファクトリメソッド）
Factory Method パターン（ファクトリメソッド・パターン）とは、GoF (Gang of Four; 四人組)によって定義されたデザインパターンの1つである。 Factory Method パターンは、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換えることで、 アプリケーションに特化したオブジェクトの生成をサブクラスに追い出し、クラスの再利用性を高めることを目的とする。
Virtual Constructor パターンとも呼ばれる。
## UML class diagram
![W3sDesign_Factory_Method_Design_Pattern_UML.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/5aafd9df-5a63-e2c0-07bd-c96a1f4adc8f.jpeg)
![1000px-Factory_Method_UML_class_diagram.svg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103595/b9848fca-7aef-a749-fb9e-fb0e219ec7db.png)
[(以上、ウィキペディア（Wikipedia）より引用)](https://ja.wikipedia.org/wiki/Factory_Method_パターン)
## □ 備忘録
[振る舞いに関する`Template Method`パターン](https://ja.wikipedia.org/wiki/Template_Method_パターン)は、スーパークラスで処理の大枠を作って、サブクラスで具体的処理を決定するというもの。この`Template Method`パターンを、インスタンスをつくる場面に適用したものが、`Factory Method`パターンらしい。

# ■ "Factory Method"のサンプルプログラム
Factory Methodパターンは、以下の特徴があるようです。

- インスタンスの作り方をスーパークラス側で定める
- 具体的なクラス名までは定めない
- 具体的な肉付けは、全てサブクラス側で行う

これによって、インスタンス作成のための枠組み（フレームワーク）と実際のインスタンス作成のクラスを分けて考えることができるようになるそうです。
実際に、Factory Methodパターンを使って、「身分証明書カード（IDカード）を作る工場」を題材としたサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

- `Hiroshi Yuki"`, `Tomura`, `Hanako Sato`の３名の身分証明書カードを作成する
- `Hiroshi Yuki"`, `Tomura`, `Hanako Sato`の３名の身分証明書カードを使用する

```
$ 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

- ディレクトリ構成

```console
.
├── Main.py
└── framework
    ├── __init__.py
    ├── factory.py
    └── idcardfactory
        ├── __init__.py
        └── id_card_factory.py
```

## (1) Product（製品）の役
`Product`役では、インスタンスが持つべきインタフェースを定めます。
サンプルプログラムでは、`Product`クラスが、この役を努めます。

```python:framework/factory.py
from abc import ABCMeta, abstractmethod

... (snip)

class Product(metaclass=ABCMeta):
    @abstractmethod
    def use(self):
        pass
```
## (2) Creator（作成者）の役
`Creator`役では、`Product`を生成する役割を担います。実際に生成する`ConcreteProduct`役については何も知りません。
さらに、`Creator`役には、インスタンスの各部分を作るためのメソッドが用意されます。
サンプルプログラムでは、`Factory`クラスが、この役を努めます。

```python:framework/factory.py
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`クラスが、この役を努めます。

```python:framework/id_card_factory.py
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`クラスが、この役を努めます。

```python:framework/id_card_factory.py
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`メソッドが、この役を努めます。

```python:Main.py
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())
```

# ■ 参考URL
- [「Java言語で学ぶデザインパターン入門」を終えて(ない)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java言語で学ぶデザインパターン入門-を終えて-ない-2cc9b34a30b2)
- [Factory Methodパターン from "tachikawa844の日記"](https://tachikawa844.hatenadiary.org/entry/20081224/1230095888)