NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

デザインパターン 「AbstractFactory」を学んで感じたメリット・デメリット

本記事は  2022年度 新人卒業記念Week  5日目の記事です。
🌸  4日目  ▶▶ 本記事 ▶▶  6日目  📚

はじめに

新人卒業ウィーク5日目を担当する新井翔太です。 このブログを書くにあたって、業務中の会話でAbstractFactoryという言葉が出てきたときに自分の中でぼんやりとしかイメージがつかめず会話についていけなかったことを思い出し、このテーマに決めました。開発者間での会話にデザインパターンが出てくることもあると思うので、知識の定着という意図でこの記事を書きました。

Abstract Factoryとは

Abstract Factoryとはオブジェクトの生成に関するデザインパターンのひとつで、オブジェクト群を抽象クラスを使用して生成します。 一般的に下記のようなクラス図で説明されることが多いと思います。

Appクラスが呼び出したいオブジェクト群はAbstractProductAクラス、AbstractProductBクラスの二つの抽象クラスであり、その二つを実装しているのがImplemetProductAクラス、ImplemetProductBクラスです。そして、そのインスタンスを生成する役割のクラスがAbstractFactoryとImplementFactoryクラスです。Factoryクラスのmake~メソッドでそれぞれのインスタンスを生成するように実装します。ここで注目すべき点はわざわざ抽象クラスを通して具象クラスにアクセスしている点です。そうすることで呼び出し元のクラスでは具象クラスの差異を感じることなく使用することが出来ます。

呼び出し元のAppクラスでは以下の記述のようにFactoryクラスを経由してAbstractProductAクラスとAbstractProductBクラスのインスタンスを生成します。

   AbstractFactory factory = new ImplementFactory();
    AbstractProductA productA = factory.makeAbstractProductA();
    AbstractProductB productB = factory.makeAbstractProductB();

Abstract Factoryパターンのメリット・デメリット

メリット

  • 現状のコードを変えることなく拡張することが出来る。

新しいオブジェクト群を追加する場合でも現状のコードを変更することなく実装することが容易になります。先の図でいうImplementFactoryクラス、ImplemetProductAクラス、ImplemetProductBクラスのような具象クラスの追加で対応することが出来ます。

  • 依存の向きを変更できる

このオブジェクト群を使用する呼び出し元のクラスからは具象クラスを見ることはないので、ProductAやProductBの変更時にAppクラスに及ぼす影響が少なくなります。

デメリット

  • オブジェクト群の数や種類が変更される変更に弱い

上記の図で言う所のAbstractFactoryのmakeProductAなどの生成するオブジェクトの数が増減するような修正に弱いです。抽象クラスを変更すると現状のコードすべてに影響が出るため、そのような修正が入りそうな場合はAbstractFactoryパターンを使うべきではないと言えます。

  • 実装が複雑になる

クラス図の通り、抽象クラスと具象クラスを使用しているので、適切な場面で使用しないと、不必要に実装を複雑化するだけになってしまいます。

使用例

例として、提出先ごとにレポート形式や出力方法が異なるレポートアプリを作成するアプリケーションを考えます。 このレポートの提出をするためにはレポートと出力の処理が必要で、これらの処理はそれぞれ提出先に合わせてカスタマイズする必要があるとします。 そのときAbstractFactoryパターンを使用すると以下のようなクラス図で考えられます。

Reportクラスはレポートを作成し、Exportクラスは出力を行うクラスです。それらを実装しているのが点線より下に記載されているReportAクラスやExportAクラスです。 呼び出し元のAppクラスでは生成する具象ファクトリークラス(ReportAFactory、ReportBFactory)を選択するだけでその後の提出先Aの処理も提出先Bの処理も同じ記述で行うことが出来ます。 もしもここで、新たな提出先のCを追加する必要があっても、以下のように提出先Cに対応した具象クラスを実装し、そのファクトリークラスを生成するだけであとは提出先AやBと同様のコードを使って処理することが出来ます。

以上のように、差異のある部分を外に出すことでシステムの中心的なコードを必要以上に触ることなく拡張することが出来ます。

最後に

AbstractFactoryパターンは濫用すれば不必要に実装を難しくし、修正時の影響も広がってしまうので使用する際は注意する必要があります。 しかし、知識として蓄えておくだけでも他の人のコードを読んだ時に理解しやすくなるなど意味はあるので、使いこなせずとも知っておいて損はないと感じました。