さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

Pythonで学ぶデザインパターン入門 Factory Methodパターン

結城先生の Java言語で学ぶデザインパターン入門 のコードを Python に書き直していくシリーズ第4段です。

Factory Methodパターンとは

前回紹介した

saruhei1989.hatenablog.com

を、インスタンス生成の際の肉付けという特定パターンで活用したものです。
つまり、サブクラスでインスタンスを生成します。

ソースコード

コードの概要

ざっくりと言うとIDカードを作成するといったコードになります。
スーパークラスに、frameworkパッケージとしてインスタンス生成を担当する Factoryクラス と生成される Product クラスが存在します。
それぞれにスーパークラスをIDカードにおける肉付けをして継承したクラスがidcardパッケージとして存在します。

ソースコード

Product

# coding: utf-8
from abc import ABCMeta, abstractmethod


class Product(metaclass=ABCMeta):

    @abstractmethod
    def use(self):
        pass
Factory
# coding: utf-8
from abc import ABCMeta, abstractmethod

from factory_method.framework.product import Product


class Factory(metaclass=ABCMeta):

    def create(self, owner: str) -> Product:
        p = self.create_product(owner)
        self.register_product(p)
        return p

    @abstractmethod
    def create_product(self, owner: str) -> Product:
        pass

    @abstractmethod
    def register_product(self, product: Product):
        pass

インスタンスを返すメソッドだけ決め打ちで処理を生成してしまって、あとはサブクラスに任せます。

IDCard (Productを継承)

# coding: utf-8
from factory_method.framework.product import Product


class IDCard(Product):

    def __init__(self, owner: str):
        print('%sのカードを作ります。' % owner)
        self.__owner = owner

    def use(self):
        print('%sのカードを使います。' % self.__owner)

    def get_owner(self) -> str:
        return self.__owner

IDCardFactory(Factoryを継承)

# coding: utf-8
from factory_method.framework.factory import Factory
from factory_method.framework.product import Product
from factory_method.idcard.id_card import IDCard


class IDCardFactory(Factory):

    def __init__(self):
        self.__owners = []

    def create_product(self, owner: str) -> Product:
        return IDCard(owner)

    def register_product(self, product: Product):
        product.__class__ = IDCard
        self.__owners.append(product.get_owner())

    def get_owners(self) -> list:
        return self.__owners

Factoryを継承したこのサブクラスで具体的にどのクラスのインスタンスを作成するかを指定します。

実行ファイル

# coding: utf-8
from factory_method.idcard.id_card_factory import IDCardFactory

if __name__ == '__main__':
    factory = IDCardFactory()
    card1 = factory.create('さるへい')
    card2 = factory.create('へいさる')
    card3 = factory.create('たかし')
    card1.use()
    card2.use()
    card3.use()

実際どう便利か

ポイントは、Factoryはサブクラスで具体的にどのインスタンスが生成されるかはわからないということです。
Factoryクラスはサブクラスの存在を一切気にする必要がありません。よってこの抽象クラスを使い回すことができます。

インスタンス生成の定形パターンがあった際などは、Factory Methodパターンを用いてコードの重複を排除できたりするのでおすすめです。