デザインパターンは、コードを理解しやすく、スケーラブルで、再利用しやすいものにするのに役立ちます。
このように、デザインパターンには、取り組むべき問題に応じてさまざまなカテゴリーがあります。
コードがモジュール化されていれば、プロジェクトに大幅な変更を加えることなく、新しい機能を追加することが容易になります。
抽象ファクトリーデザインパターンは、密接に関連するオブジェクトのインターフェースを、そのクラスを指定せずに作成するためのフレームワークを提供する創造的なパターンである-これが「抽象」という言葉の由来である。
抽象クラスは部分的に実装され、その子クラスが持つべき要件や一般的な子クラスの動作、またどのような機能を持つべきかを定義するものである。
具体クラスは抽象クラスを拡張し、共通する機能を継承しつつ、未実装の機能を提供する。
Pythonの抽象クラス
Pythonの抽象クラスについて説明します。
> 例えば、すべての Animal
には eat()
関数があり、すべての動物に共通して実装されていますが、それぞれ独自の speak()
関数を持っているので、抽象クラス Animal
はそれを子動物に委ねます。
Python では、すべての抽象クラスは abc
モジュールの ABC
クラスから派生しています。
抽象メソッドは抽象クラスの内部で宣言されますが、実装されることはなく、実装されたメソッドはすべて具象クラスに受け継がれます。
以下の例では、 AbstractClass
の定義に @abstractmethod
デコレーターが含まれていることに注目してください。
このデコレータで関数をデコレートすることで、すべての子クラスは func()
メソッドの実装を持たなければならないと定義しています(デフォルトで共通の実装は存在しないため)。
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def func():
pass
親の抽象ファクトリークラスの部分的な実装は、その子クラス/具象クラスによって実現されます。
それぞれの子クラスは func()
メソッドを含んでおり、抽象クラスの要求を満たします。
前の例から発展して、次のような子クラスを作ることができます。
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def func(self):
pass
class ChildClass(AbstractClass):
def func(self):
out = "This is an output"
return out
obj = ChildClass()
print(obj.func())
Pythonの抽象ファクトリーデザインパターン
抽象ファクトリーパターンの定義に戻ります。
ということです。
抽象ファクトリーパターンでは、関連するオブジェクトのファミリーを作成するために、具体的なクラスを指定せずにインターフェースを定義します。
ということです。
抽象ファクトリーパターンは、オブジェクトの生成を別のクラスに委ねるパターンです。
このパターンは、あるオブジェクトの実装を抽象化して、複数のカテゴリーを作りたい場合に最適です。
ファクトリーという概念はよく知られていると思いますが、これは他のオブジェクトを生成するオブジェクトのことです。
Abstract Factoryパターンは、主にファクトリーオブジェクトのインターフェースに関係している。
オブジェクトのファミリとは?
>
テーブルには、円形、四角形、楕円形があります。
同じような意味で、「従業員」のような共通のクラスは、さらにいくつかの具象クラスに枝分かれすることがあります。
抽象ファクトリーパターンを視覚的に表現すると、以下のようになります。
2つの製品(ブラウザとメッセンジャー)からなるファミリーを設計していると仮定します。
- 抽象的な製品。ブラウザとメッセンジャーの2つの抽象クラスが作成されます。これらのクラスには、製品を構築する上で必須となる抽象的なメソッドが含まれています。これらの抽象クラスは、インターフェースと呼ばれます。
上記の例では、Web BrowserとMessengerが抽象製品にあたります。
* 具体的製品。
具体的製品:抽象クラスであるアブストラクトプロダクトから抽象メソッドを継承した製品。
インターフェイスを利用することで、さまざまな製品ファミリーを作ることができる。
例えば、上の図では、3組のユーザーに対して3種類のウェブブラウザが作成されています。
これらの具体的な製品に共通するものがあるとすれば、それは抽象クラスで定義された抽象メソッドでしょう。
* コンクリート・ファクトリー 具体的な工場は、抽象的な工場から指示された具体的な製品を作成します。
例えば、BrowserFactory
はブラウザを作成し、MessengerFactory
はメッセンジャーを作成します。
逆に、いくつかの共通機能に着目して、基本的なウェブブラウザやメッセンジャーのインスタンスを作成する BasicFactory
や SecureFactory
を作成することができます。
上記の図では、Vanilla Products Factoryはバニラの具体的な製品(ブラウザとメッセンジャー)の両方を作成することができ、Secure Products Factoryは安全なバージョンを作成することができます。
* 抽象ファクトリー。
抽象ファクトリー:抽象製品を作成するためのインターフェース、すなわち、抽象製品を返すメソッドをいくつか持っているファクトリー。
この例では、Web ブラウザーとメッセンジャーという抽象的な製品を取得するために、具象ファクトリーのインターフェイスが呼び出されます。
実装
用語の意味を理解した上で、PythonでAbstract Factoryパターンを実装してみましょう。
まず、抽象的なプロダクトである Browser
と Messenger
を作成します。
from abc import ABC, abstractmethod
class Browser(ABC):
"""
Creates "Abstract Product A"
"""
# Interface - Create Search Toolbar
@abstractmethod
def create_search_toolbar(self):
pass
# Interface - Create Browser Window
@abstractmethod
def create_browser_window(self):
pass
class Messenger(ABC):
"""
Creates "Abstract Product B"
"""
@abstractmethod
# Interface - Create Messenger Window
def create_messenger_window(self):
pass
これらは、以下の具象クラス、すなわち抽象製品のバリアントであるバニラとセキュアのベースクラスとして機能します。
class VanillaBrowser(Browser):
"""
Type: Concrete Product
Abstract methods of the Browser base class are implemented.
"""
# Interface - Create Search Toolbar
def create_search_toolbar(self):
print("Search Toolbar Created")
# Interface - Create Browser Window]
def create_browser_window(self):
print("Browser Window Created")
class VanillaMessenger(Messenger):
"""
Type: Concrete Product
Abstract methods of the Messenger base class are implemented.
"""
# Interface - Create Messenger Window
def create_messenger_window(self):
print("Messenger Window Created")
class SecureBrowser(Browser):
"""
Type: Concrete Product
Abstract methods of the Browser base class are implemented.
"""
# Abstract Method of the Browser base class
def create_search_toolbar(self):
print("Secure Browser - Search Toolbar Created")
# Abstract Method of the Browser base class
def create_browser_window(self):
print("Secure Browser - Browser Window Created")
def create_incognito_mode(self):
print("Secure Browser - Incognito Mode Created")
class SecureMessenger(Messenger):
"""
Type: Concrete Product
Abstract methods of the Messenger base class are implemented.
"""
# Abstract Method of the Messenger base class
def create_messenger_window(self):
print("Secure Messenger - Messenger Window Created")
def create_privacy_filter(self):
print("Secure Messenger - Privacy Filter Created")
def disappearing_messages(self):
print("Secure Messenger - Disappearing Messages Feature Enabled")
抽象的なメソッドとは別に、それぞれのコンテキストで機能するように具象製品に追加された機能があることにお気づきでしょう。
あと少しです。
では、抽象ファクトリー自身とそれに対応する具象ファクトリーを作ってみましょう。
class AbstractFactory(ABC):
"""
The Abstract Factory
"""
@abstractmethod
def create_browser(self):
pass
@abstractmethod
def create_messenger(self):
pass
class VanillaProductsFactory(AbstractFactory):
"""
Type: Concrete Factory
Implement the operations to create concrete product objects.
"""
def create_browser(self):
return VanillaBrowser()
def create_messenger(self):
return VanillaMessenger()
class SecureProductsFactory(AbstractFactory):
"""
Type: Concrete Factory
Implement the operations to create concrete product objects.
"""
def create_browser(self):
return SecureBrowser()
def create_messenger(self):
return SecureMessenger()
上のコードでは、AbstractFactory
が基底クラスとして動作しているので、基底クラスで述べたように抽象的なメソッドがインスタンス化されます。
それでは、 main()
メソッドを追加して、この例の動きを見てみましょう。
def main():
for factory in (VanillaProductsFactory(), SecureProductsFactory()):
product_a = factory.create_browser()
product_b = factory.create_messenger()
product_a.create_browser_window()
product_a.create_search_toolbar()
product_b.create_messenger_window()
if __name__ == "__main__":
main()
コード全体を見たい場合は、GitHub のリポジトリで見ることができます。
このコードを実行すると、セキュアブラウザとセキュアメッセンジャーが作成されたことを示す、次のような出力が返されます。
$ python3 abstract_factory_code.py
Browser Window Created
Search Toolbar Created
Messenger Window Created
Secure Browser - Browser Window Created
Secure Browser - Search Toolbar Created
Secure Messenger - Messenger Window Created
長所と短所
さて、このパターンを実装したところで、その長所と短所を考えてみましょう。
長所
- このパターンの主な利点は柔軟性です。既存の製品に新しい機能や特徴を追加したり、あるいはコンクリートファクトリに新しいコンクリート製品を追加したりすることが可能です。これは、コード全体を妨害することなく行うことができます。
- クライアントと具体的な製品の間の直接的な相互作用は最小限に抑えられています。また、コードの整理やコンパクト化にも柔軟性があります。
短所
- このパターンの主な欠点は、コードの可読性と保守性である。新しいフューチャーを追加する柔軟な方法を提供するが、新しいコンポーネントを追加するには、具象クラスへの追加、インターフェイスの修正などが必要となる。修正によるカスケード効果で開発時間がかかる。
結論
Abstract Factoryパターンは、単一種類の製品にしか使えないFactoryパターンとは異なり、密接に関連した異なる製品のファミリーに非常に効果的に使用することができる。
>
もし、もっと詳しく知りたい場合は、PythonのFactory Patternのガイドを読んでください。
Abstract Factoryパターンは、クリーンなコードを書く必要性という大きな危機を解決するものです。
私たちはこのパターンの基本をカバーし、また、例を使って実装を理解しました。