設計を意識したコードが書けるようになる為に、デザインパターン修行しました。
他のDesign Patternもちょくちょく出していきます。
前置き
- 増補改訂版Java言語で学ぶデザインパターン入門をJavaからPythonにしてます。(Pythonは3.4.2)
- githubにコード置いてあります(まだ動かないものもある)
デザインパターンをどういう時に、何を、どう使うのかを理解することが一先ずの目標。
(Javaというか静的型付言語は初めてで、且つpython歴もそんなに長くないので、Pythonistaぽっくないところがあると思います。ご指摘ございましたらご教授ください。)
今回は、生成に関するパターンFactoryMethod。
FactoryMethodとは
オブジェクト作成のインタフェースと、オブジェクト生成する役割りを分けて、他のクラスのコンストラクタをサブクラスで上書き可能な自分のメソッドに置き換え、オブジェクトの生成をサブクラスに任せて、クラスの再利用性を高める。
概要
このサンプルプログラムは、身分証明書カード(IDカード)を作る工場を題材としたものです。ここでは4つのクラスが登場します。
ProductクラスとFactoryクラスは、Frameworkというパッケージに属しています。この2つのクラスがインスタンス生成のための枠組み(フレームワーク)の役割を果たします。
IDクラスとIDCardFactoryクラスは、実際の肉付けを行います。これらはIDCardというパッケージに属しています。
全体のクラス図
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パターンが使われる。
from abc import ABCMeta, abstractmethod
class Product(metaclass=ABCMeta):
@abstractmethod
def use(self):
pass
抽象メソッドuseの宣言だけ。
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メソッドを定義。
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に追加している。
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()
出力結果
結城浩のカードを作成します
とむらのカードを作成します
佐藤花子のカードを作成します
結城浩のカードを使います
とむらのカードを使います
佐藤花子のカードを使います
##まとめ
インタフェースだけ規定して、サブクラスがどちらのクラスをインスタンス化するか任されているので、内部の実装は気にせず、外部からメソッドにアクセスをすることができました。