【ITニュース解説】🧠 Demystifying the Factory Method Pattern with a Manabita Twist
2025年09月13日に「Dev.to」が公開したITニュース「🧠 Demystifying the Factory Method Pattern with a Manabita Twist」について初心者にもわかりやすく解説しています。
ITニュース概要
Factory Methodは、オブジェクトの生成を特定のメソッドに任せる「生成に関するデザインパターン」だ。これにより、具体的なクラスを知らずに共通のインターフェースで操作でき、コードの柔軟性が高まる。支払いシステムなど、多様なオブジェクトを扱う場面で活用される。
ITニュース解説
Factory Methodパターンとは、プログラムがオブジェクトを作成する際に、そのオブジェクトの具体的なクラスを指定せずに生成できるようにする設計手法である。これは「生成に関するデザインパターン」の一つとして知られている。一見複雑に聞こえるかもしれないが、その目的はコードの柔軟性と保守性を高めることにある。
例えば、あるプログラムがオブジェクトを生成する必要があるものの、具体的にどの種類のオブジェクトを作るべきか、その時点では確定していない状況を想像すると分かりやすい。それは、設定ファイルの内容、プログラムに渡されたパラメータ、あるいは実行時の環境など、さまざまな要因によって生成するオブジェクトが変わる可能性がある場合である。このような状況で、もしオブジェクトの種類ごとに「もしこれならAを作る、もしあれならBを作る」といった条件分岐(if-elseやswitch文)を直接コードの中に詰め込んでしまうと、新しい種類のオブジェクトが追加された場合や、既存のオブジェクトの生成方法が変わった場合に、多くの箇所を修正する必要が生じ、コードが読みにくく、変更に弱くなってしまう。
Factory Methodパターンは、この問題を解決するために、オブジェクト生成の責任を「ファクトリメソッド」と呼ばれる特別なメソッドに委譲する。これにより、メインのプログラムは具体的なオブジェクトの種類を知る必要がなくなり、共通のインターフェースを通じてオブジェクトとやり取りできるようになる。これは、プログラムの主要なロジックが、オブジェクトの具体的な実装に左右されずに機能することを意味し、非常に高い柔軟性をもたらす。
この概念を具体例で見てみよう。あるシステムが多様な支払い方法を処理するケースを考える。
まず、すべての支払い方法が共通して持つべき振る舞いを定義する「製品」としてのインターフェースを作成する。このインターフェースはPaymentと名付けられ、doPayment()という支払い処理を実行するメソッドを持つ。これにより、どの支払い方法も「支払いを行う」という共通の契約に従うことになる。
次に、このPaymentインターフェースを実装する具体的な支払い方法のクラス群を作成する。例えば、クレジットカードでの支払いを行うCardPayment、Google Payでの支払いを行うGooglePayment、PayPalでの支払いを行うPaypalPaymentといったクラスがこれに該当する。これらのクラスはそれぞれdoPayment()メソッドを独自に実装し、「カードで支払う」「Google Payで支払う」といった具体的な処理を記述する。
ここでFactory Methodパターンの「魔法」が登場する。PaymentFactoryというクラスを作成し、このクラスの唯一の仕事は、与えられたパラメータに基づいて適切なPaymentオブジェクトを生成して返すことである。例えば、buildPaymentという静的メソッドを定義し、支払い方法の種類(例:TypePaymentという列挙型)を引数として受け取る。このbuildPaymentメソッドの内部で、switch文を使って引数の種類を判断し、CARDであればnew CardPayment()を、GOOGLEであればnew GooglePayment()を、PAYPALであればnew PaypalPayment()をそれぞれ生成して返す。もし未対応の支払いタイプが指定された場合は、エラーを通知する。
このようにすることで、システムの主要部分は顧客が選択した支払い方法の種類(カード、Google Pay、PayPalなど)をPaymentFactoryに渡しさえすればよい。PaymentFactoryは、その情報に基づいて適切なPaymentオブジェクトを生成し、メインのシステムに返す。メインのシステムは、返されたオブジェクトがどの具体的な支払い方法のインスタンスであるかを気にすることなく、ただdoPayment()メソッドを呼び出すだけでよい。なぜなら、すべての支払いオブジェクトはPaymentインターフェースを実装しており、必ずdoPayment()メソッドを持っているからである。これにより、新しい支払い方法が追加されても、PaymentFactoryと新しい支払い方法のクラスを追加するだけで済み、既存のシステムコードへの影響を最小限に抑えることができる。
もう一つの例として、エクアドル・マナビ州のシーフードレストランを想像してみよう。このレストランでは「セビーチェ」という料理を提供するが、セビーチェには魚、エビ、ミックスなど複数のバリエーションがある。これらはすべて「セビーチェ」というカテゴリに属するが、それぞれ調理法や材料が少しずつ異なる。
この状況もFactory Methodパターンを適用するのに適している。まず、すべてのセビーチェが共通して持つべき振る舞いを定義するCevicheインターフェースを作成する。次に、FishCeviche、ShrimpCeviche、MixedCevicheといった具体的なセビーチェのクラスをこのインターフェースを実装して作成する。そして、ManabitaRestaurantFactoryのようなファクトリクラスを作成し、CevicheType(セビーチェの種類を示す列挙型)などのパラメータに基づいて適切なCevicheオブジェクトを生成して返すメソッドを提供する。
このように、Factory Methodパターンは、オブジェクトの生成ロジックを特定のクラスから分離し、一元化することで、システムの柔軟性、拡張性、そして保守性を向上させる。具体的なオブジェクトを生成する責任をファクトリに集中させることで、コードがよりクリーンになり、将来の変化にも対応しやすくなるのである。