Posted at

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

More than 3 years have passed since last update.

設計を意識したコードが書けるようになる為に、デザインパターン修行しました。

他の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()


出力結果



結城浩のカードを作成します

とむらのカードを作成します

佐藤花子のカードを作成します

結城浩のカードを使います

とむらのカードを使います

佐藤花子のカードを使います


まとめ

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


参考