デザインパターン(Design Pattern) #Factory Method


設計を意識したコードが書けるようになる為に、デザインパターン修行しました。
他のDesign Patternもちょくちょく出していきます。

前置き

デザインパターンをどういう時に、何を、どう使うのかを理解することが一先ずの目標。
(Javaというか静的型付言語は初めてで、且つpython歴もそんなに長くないので、Pythonistaぽっくないところがあると思います。ご指摘ございましたらご教授ください。)

今回は、生成に関するパターンFactoryMethod。

FactoryMethodとは

オブジェクト作成のインタフェースと、オブジェクト生成する役割りを分けて、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換え、オブジェクトの生成をサブクラスに任せて、クラスの再利用性を高める。

概要

このサンプルプログラムは、身分証明書カード(IDカード)を作る工場を題材としたものです。ここでは4つのクラスが登場します。

ProductクラスとFactoryクラスは、Frameworkというパッケージに属しています。この2つのクラスがインスタンス生成のための枠組み(フレームワーク)の役割を果たします。

IDクラスとIDCardFactoryクラスは、実際の肉付けを行います。これらはIDCardというパッケージに属しています。

全体のクラス図

Framework/factory.py
from abc import ABCMeta, abstractmethod


class Factory(metaclass=ABCMeta):

    @abstractmethod
    def _create_product(self, owner):
        pass

    @abstractmethod
    def _register_product(self, product):
        pass

    def create(self, owner):
        self.__p = self._create_product(owner)
        self._register_product(self.__p)
        return self.__p

ここではTemplate Methodパターンが使われている。Template Methodパターンは「スーパークラスで処理の大きな枠組みを決めておいて、サブクラスでその具体的処理を決める」こと。

このクラスは処理の大きな枠組みを規定し、具体的な処理が決まっていないcreate_productとregister_productの両メソッドの実装をサブクラスが担う。

createメソッドではcreate_productとregister_productの両メソッドを使って「製品」のインスタンスを生成している。
Factory Methodパターンではインスタンス生成にTemplate Methodパターンが使われる。

Framework/product.py
from abc import ABCMeta, abstractmethod

class Product(metaclass=ABCMeta):

    @abstractmethod
    def use(self):
        pass

抽象メソッドuseの宣言だけ。

IDCard/idcard.py
from Framework.product import Product


class IDCard(Product):

    def __init__(self, owner):
        self.__owner = owner
        print(self.__owner + 'のカードを作成します')

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

    def get_owner(self):
        return self.__owner

Productクラスのサブクラスとして定義、コンストラクタを作り、useメソッドとget_ownerメソッドを定義。

IDCard/idcard_factory.py
from Framework.factory import Factory
from IDCard.idcard import IDCard


class IDCardFactory(Factory):

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

    def _create_product(self, owner):
        return IDCard(owner)

    def _register_product(self, product):
        self.__registed.append(product.get_owner())

create_productとregister_productメソッドを実装。
create_productメソッドはIDCardクラスのインスタンスを生成する。
register_productメソッドはget_ownerメソッドで得たIDCardのownerをリストownersに追加している。

main.py
from IDCard.idcard_factory import IDCardFactory


def main():
    factory = IDCardFactory()
    card1 = factory.create('結城浩')
    card2 = factory.create('とむら')
    card3 = factory.create('佐藤花子')

    card1.use()
    card2.use()
    card3.use()

if __name__ == '__main__':
    main()

出力結果

結城浩のカードを作成します
とむらのカードを作成します
佐藤花子のカードを作成します
結城浩のカードを使います
とむらのカードを使います
佐藤花子のカードを使います

まとめ

インタフェースだけ規定して、サブクラスがどちらのクラスをインスタンス化するか任されているので、内部の実装は気にせず、外部からメソッドにアクセスをすることができました。

参考