趣旨
駆け出しエンジニアの備忘録の垂れ流し。
※ 出典漏れがあればご指摘ください
出典:
https://yamakatsusan.web.fc2.com/pythonpattern08.html
https://dackdive.hateblo.jp/entry/python-design-pattern/abstract-factory
https://www.oreilly.co.jp/books/9784873117393/
abstract factoryパターン概要
生成方法がほぼ同様の手順で、かつ、複数のクラスのインスタンス(Product)の生成が発生するようなドメインの実装をするにあたり、Factoryクラスを作ることで、生成処理の実装をシンプルに、かつclient側から作成の責務を分離する。
Productクラスのインスタンスの生成にあたり、Clientに生成するためのインターフェースを提供するFactoryクラスを実装する。Factoryクラスはお手本となるAbstract Factoryに則った実装となる。
Clientの関心事は部品を使うことであり、どんな部品であっても作ることはFactoryに任せることが可能となる。
(Clientは、具象Factoryを指定し、生成のためのインターフェースを呼び出すだけで良い)
クラス図とシーケンス図
wikipediaより引用
実装方針
- AbstractFactoryクラスではtemplate methodのようにProductインスタンス作成手順(必須メソッド)を規定する。
- Factoryサブクラスでは必須メソッドをオーバーライドする。
- ClientではFactoryサブクラスを呼び出し(生成し)、インターフェースを呼び出す処理を実装する
- Client側では呼び出すFactoryクラスの指定が必要。Factoryクラスを決定するメソッドがAbstractFactoryクラスにあると便利。これは
@classmethod
を利用して実現可能。また、Factoryクラスインスタンスの生成をしないで、productインスタンスの生成が行えるようになる。- classmethodの用法の1つに、自身のインスタンスを生成する手段としての用法がある。
- 応用として、どのクラスのインスタンスを生成するか決定するロジックをもたせることで、
AbstractFactoryのみの指定で、具象factoryのimportを不要とすることも可能。
# factory側
class AbstractFactory:
@abstractmethod
def create_product1(self):
pass
@abstractmethod
def create_product2(self):
pass
@classmethod
def get_factory(cls, some_args):
selected_class = get_class(some_args) # クラスを指定するロジックを記載
return selected_class()
class FactoryA(AbstractFactory):
def create_product1(self):
# 実処理を記載
return Product1A()
def create_product2(self):
# 実処理を記載
return Product2A()
# client側
def main():
factory = AbstractFactory.get_factory(choose_some_keywords_for_selecting_cls)
product_1 = factory.create_product1()
product_2 = factory.create_product2()
# class内クラスにproductクラスを記載するパターン
# 生成するProductが簡単ならこちらでもOK
# factory側
class AbstractFactory:
@classmethod
def create_product1(cls):
return cls.Product1()
@abstractmethod
def create_product2(self):
return cls.Product2()
class FactoryA(AbstractFactory):
class Product1:
pass
class Product2:
pass
# client側
def main():
product_1 = AbstractFactory.create_product1(FactoryA)
product_2 = AbstractFactory.create_product2(Factory)
メリットと使い所
- メリット
- インスタンス生成のロジックが、clientコードに依存しない(インターフェースに依存する)。
- 作り方、作るもの、実際に作る、を別のモジュールに実装できる
- 使い所
- 生成方法がほぼ共通の場合に効果がある
- 1つのFactoryクラスにて生成するProductの種類が増えることへの変化には弱い
## わかってないこと
1つのFactoryクラスにて生成するProductの種類が増えることへの変化には弱い
どのように対応(リファクタリング)するのか?