抽象ファクトリーパターン

抽象ファクトリーパターン(Abstract Factory Pattern)は、スーパーファクトリーを中心として他のファクトリーを作成します。このスーパーファクトリーは、他のファクトリーのファクトリーとも呼ばれます。このタイプのデザインパターンは生成系パターン(クリエイショナルパターン)に属し、オブジェクトを作成する最良の方法を提供します。

抽象ファクトリーパターンでは、インターフェースは関連するオブジェクトを作成するファクトリーの役割を担い、それらのクラスを明示的に指定する必要はありません。生成された各ファクトリーは、ファクトリーパターンに従ってオブジェクトを提供できます。

抽象ファクトリーパターンは、具体的な実装クラスを指定することなく、一連の関連するオブジェクトまたは相互依存するオブジェクトを作成するためのインターフェースを提供します。抽象ファクトリーパターンを使用することで、クライアントと具体的な製品の作成プロセスを分離(デカップリング)し、クライアントがファクトリーインターフェースを通じて製品群を作成できるようにします。

概要

意図

一連の関連するオブジェクトまたは相互依存するオブジェクトを作成するためのインターフェースを提供し、それらの具体的なクラスを指定する必要はありません。

主な解決

インターフェースの選択に関する問題。

適用シナリオ

システムが複数の関連オブジェクトや依存オブジェクトを作成する必要があり、具体的なクラスを指定する必要がない場合。

解決策

製品ファミリー内で複数の製品を定義し、具象ファクトリーがこれらの製品を作成するメソッドを実装します。

キーコード

1つのファクトリーに複数の同種製品の作成メソッドを集約します。

応用例

異なるタイプのワードローブがあるとします。各ワードローブ(具象ファクトリー)は、ビジネススーツ、ファッションウェアなど、1種類の衣類(セットになった具象製品)しか収納できません。各セットには、具体的な上着とズボン(具象製品)が含まれます。すべてのワードローブはワードローブクラス(抽象ファクトリー)の具体的な実装であり、すべての上着とズボンは、それぞれ上着インターフェースとズボンインターフェース(抽象製品)を実装します。

長所

  1. 同じ製品ファミリーのオブジェクトが一緒に動作することを保証します。
  2. クライアントは各オブジェクトの具体的なクラスを知る必要がなく、コードが簡素化されます。

短所

製品ファミリーの拡張は非常に困難です。新しい製品ファミリーを追加するには、抽象ファクトリーとすべての具象ファクトリーのコードを変更する必要があります。

使用シーン

  1. QQでスキンを変更する場合、スキン一式をまとめて変更します。
  2. クロスプラットフォームアプリケーションを作成する際に、異なるオペレーティングシステム向けのプログラムを生成します。

注意事項

新しい製品ファミリーの追加は比較的容易ですが、新しい製品の階層構造の追加は困難です。

構造

抽象ファクトリーパターンには、次の主要なロール(役割)が含まれます。

  • 抽象ファクトリー(Abstract Factory):製品オブジェクトを作成するための一連のメソッドを宣言します。各メソッドは1つの製品タイプに対応します。抽象ファクトリーはインターフェースまたは抽象クラスにできます。
  • 具象ファクトリー(Concrete Factory):抽象ファクトリーインターフェースを実装し、具体的な製品オブジェクトのインスタンスを作成します。
  • 抽象製品(Abstract Product):一連の製品オブジェクトの共通インターフェースまたは抽象クラスを定義し、製品オブジェクトのパブリックメソッドを記述します。
  • 具象製品(Concrete Product):抽象製品インターフェースを実装し、具体的な製品の特定の動作と属性を定義します。

抽象ファクトリーパターンは通常、関連する製品群(ファミリー)を扱います。各具象ファクトリークラスは、その製品群内の具象製品を作成します。クライアントは抽象ファクトリーインターフェースを使用して製品オブジェクトを作成するため、具象製品の実装クラスを直接使用する必要はありません。

実装

作成するのはShapeとColorインターフェースと、そのインターフェースを実装するエンティティクラスです。次のステップでは、抽象ファクトリークラスを作成します。AbstractFactory。次に、ファクトリークラスを定義します。ShapeFactoryとColorFactory、これら2つのファクトリークラスはどちらも拡張したものです。AbstractFactory。次に、ファクトリークリエイター/ジェネレータークラスを作成します。FactoryProducer。

AbstractFactoryPatternDemoクラスは、FactoryProducerを使用して取得しますAbstractFactoryオブジェクトを。これはAbstractFactoryに形状情報を渡しますShape(CIRCLE / RECTANGLE / SQUARE)、必要なオブジェクトのタイプを取得するためです。同時に、AbstractFactoryに色情報を渡しますColor(RED / GREEN / BLUE)、必要なオブジェクトのタイプを取得するためです。

抽象工厂模式的 UML 图

ステップ 1

形状(シェイプ)用のインターフェースを作成します。

Shape.java

public interface Shape { void draw(); }

ステップ 2

インターフェースを実装するエンティティクラスを作成します。

Rectangle.java

Rectangle.java

public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }

Square.java

public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }

Circle.java

public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }

ステップ 3

色(カラー)用のインターフェースを作成します。

Color.java

public interface Color { void fill(); }

ステップ4

インターフェースを実装するエンティティクラスを作成します。

Red.java

public class Red implements Color { @Override public void fill() { System.out.println("Inside Red::fill() method."); } }

Green.java

public class Green implements Color { @Override public void fill() { System.out.println("Inside Green::fill() method."); } }

Blue.java

public class Blue implements Color { @Override public void fill() { System.out.println("Inside Blue::fill() method."); } }

ステップ 5

Color および Shape オブジェクト用の抽象クラスを作成して、ファクトリーを取得します。

AbstractFactory.java

public abstract class AbstractFactory { public abstract Color getColor(String color); public abstract Shape getShape(String shape); }

ステップ 6

AbstractFactory を拡張したファクトリークラスを作成し、指定された情報に基づいてエンティティクラスのオブジェクトを生成します。

ShapeFactory.java

public class ShapeFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } @Override public Color getColor(String color) { return null; } }

ColorFactory.java

public class ColorFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ return null; } @Override public Color getColor(String color) { if(color == null){ return null; } if(color.equalsIgnoreCase("RED")){ return new Red(); } else if(color.equalsIgnoreCase("GREEN")){ return new Green(); } else if(color.equalsIgnoreCase("BLUE")){ return new Blue(); } return null; } }

ステップ 7

形状または色の情報を渡すことによってファクトリーを取得する、ファクトリークリエイター/ジェネレータークラスを作成します。

FactoryProducer.java

public class FactoryProducer { public static AbstractFactory getFactory(String choice){ if(choice.equalsIgnoreCase("SHAPE")){ return new ShapeFactory(); } else if(choice.equalsIgnoreCase("COLOR")){ return new ColorFactory(); } return null; } }

ステップ 8

FactoryProducer を使用して AbstractFactory を取得し、タイプ情報を渡すことでエンティティクラスのオブジェクトを取得します。

AbstractFactoryPatternDemo.java

public class AbstractFactoryPatternDemo { public static void main(String[] args) { //形状ファクトリーを取得します AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); //形状が Circle のオブジェクトを取得します Shape shape1 = shapeFactory.getShape("CIRCLE"); //Circle の draw メソッドを呼び出します shape1.draw(); //形状が Rectangle のオブジェクトを取得します Shape shape2 = shapeFactory.getShape("RECTANGLE"); //Rectangle の draw メソッドを呼び出します shape2.draw(); //形状が Square のオブジェクトを取得します Shape shape3 = shapeFactory.getShape("SQUARE"); //Square の draw メソッドを呼び出します shape3.draw(); //色ファクトリーを取得します AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); //色が Red のオブジェクトを取得します Color color1 = colorFactory.getColor("RED"); //Red の fill メソッドを呼び出します color1.fill(); //色が Green のオブジェクトを取得します Color color2 = colorFactory.getColor("GREEN"); //Green の fill メソッドを呼び出します color2.fill(); //色が Blue のオブジェクトを取得します Color color3 = colorFactory.getColor("BLUE"); //Blue の fill メソッドを呼び出します color3.fill(); } }

ステップ 9

プログラムを実行し、結果を出力します:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
その他の拡張