抽象工場パターン(Abstract Factory Pattern)は、具象クラスを明示的に指定することなく、関連し合う一連のオブジェクト群(製品ファミリー)を生成するためのインターフェースを提供する生成に関するデザインパターンです。
解決する課題と設計アプローチ
システム内で複数のオブジェクトを生成する必要があり、それらが互いに依存関係や制約を持つ場合にこのパターンが有効です。抽象工場は、クライアントに対してオブジェクト生成の統一されたAPIを提供します。実際の生成ロジックは具象ファクトリのサブクラスに委譲されるため、同じ抽象工場インターフェースに対して異なる実装を提供でき、製品間の整合性を厳密に保つことができます。
パターンの構成要素
- 抽象工場 (Abstract Factory): 一連の製品オブジェクトを生成するための操作を宣言するインターフェース。
- 具象工場 (Concrete Factory): 抽象工場のメソッドを実装し、特定の製品ファミリーを生成する具象クラス。
- 抽象製品 (Abstract Product): 製品オブジェクトの各カテゴリに対するインターフェース。
- 具象製品 (Concrete Product): 抽象製品を実装した実際のオブジェクト。具象工場によってインスタンス化される。
- クライアント (Client): 抽象工場と抽象製品のインターフェースのみを利用して処理を行うコンポーネント。
標準的な実装例:クロスプラットフォームUIコンポーネント
以下のC#コードは、異なるオペレーティングシステム向けのUIコンポーネント(ボタンとチェックボックス)を生成する抽象工場の実装例です。
namespace DesignPatterns.AbstractFactory.UI
{
// 抽象製品インターフェース
public interface IButton
{
void Render();
}
public interface ICheckbox
{
void Render();
}
// 具象製品:Mac用コンポーネント
public class MacButton : IButton
{
public void Render() => Console.WriteLine("MacOSスタイルのボタンを描画します。");
}
public class MacCheckbox : ICheckbox
{
public void Render() => Console.WriteLine("MacOSスタイルのチェックボックスを描画します。");
}
// 具象製品:Windows用コンポーネント
public class WindowsButton : IButton
{
public void Render() => Console.WriteLine("Windowsスタイルのボタンを描画します。");
}
public class WindowsCheckbox : ICheckbox
{
public void Render() => Console.WriteLine("Windowsスタイルのチェックボックスを描画します。");
}
// 抽象工場インターフェース
public interface IUiComponentFactory
{
IButton CreateButton();
ICheckbox CreateCheckbox();
}
// 具象工場:Mac用ファクトリ
public class MacUiFactory : IUiComponentFactory
{
public IButton CreateButton() => new MacButton();
public ICheckbox CreateCheckbox() => new MacCheckbox();
}
// 具象工場:Windows用ファクトリ
public class WindowsUiFactory : IUiComponentFactory
{
public IButton CreateButton() => new WindowsButton();
public ICheckbox CreateCheckbox() => new WindowsCheckbox();
}
}
パターンの特徴と実装の指針
製品ファミリーの制約とインターフェース設計
抽象工場の主要な役割は、関連性のあるオブジェクト群を生成するためのインターフェースを定義することです。インターフェース内に定義されるメソッドは、無作為に配置されるのではなく、同一の製品ファミリーを構成するための関連メソッドとして設計される必要があります。
インターフェースとしての実装
JavaやC#などのオブジェクト指向言語では、抽象工場は通常interfaceとして実装されます。名前の中に「Abstract(抽象)」が含まれているため抽象クラス(abstract class)と誤解されやすいですが、製品ファミリーに共通のデフォルト動作や状態を持たせる必要がある場合を除き、インターフェースを使用するのが一般的です。
拡張可能なパラメータ化ファクトリの設計
製品の種類が非常に多い場合、抽象工場インターフェースに多数のメソッドを定義するとインターフェースが肥大化します。これを防ぐため、単一のファクトリメソッドに識別子(パラメータ)を渡し、生成するオブジェクトを動的に切り替えるアプローチが有効です。この場合、戻り値の型はすべての具象製品が実装する共通のベースインターフェースやobject型になります。
namespace DesignPatterns.AbstractFactory.Hardware
{
// すべてのハードウェアコンポーネントのベースインターフェース
public interface IHardwareComponent
{
string GetSpecification();
}
// 具象製品
public class HighEndCpu : IHardwareComponent
{
public string GetSpecification() => "High-End CPU: 16 Cores, 5.0 GHz";
}
public class GamingGpu : IHardwareComponent
{
public string GetSpecification() => "Gaming GPU: 12GB VRAM, Ray Tracing";
}
public class ATXMotherboard : IHardwareComponent
{
public string GetSpecification() => "ATX Motherboard: Z790 Chipset";
}
// コンポーネントの種類を定義する列挙型
public enum ComponentType
{
Processor,
GraphicsCard,
Mainboard
}
// パラメータ化された具象ファクトリ
public class PcBuilderFactory
{
public IHardwareComponent CreateComponent(ComponentType type)
{
return type switch
{
ComponentType.Processor => new HighEndCpu(),
ComponentType.GraphicsCard => new GamingGpu(),
ComponentType.Mainboard => new ATXMotherboard(),
_ => throw new ArgumentException("サポートされていないコンポーネントタイプです。", nameof(type))
};
}
}
}