blog

GoFデザインパターン|抽象ファクトリーパターン

いわゆる抽象ファクトリーパターンは、特定のクラスを明示的に指定することなく、関連または依存するオブジェクトのファミリーを作成するためのインターフェイスを提供します。これにより、クライアントは抽象インタ...

May 4, 2020 · 5 min. read
シェア

今日は、3つ目のデザインパターンであるAbstract Factoryパターンについて学びます。

概念

いわゆる抽象ファクトリーパターンは、特定のクラスを明示的に指定することなく、関連または依存するオブジェクトのファミリーを作成するためのインターフェースを提供します。これにより、クライアントは抽象インターフェースを使用して、実際に出力される具体的な製品が何であるかを気にすることなく、関連する製品のセットを作成することができます。このようにして、クライアントは具体的な製品から切り離されます。利点は、具体的なクラスの生成を分離することで、クライアントが何が作成されたかを知る必要がないことです。一方、欠点は、新しい製品オブジェクトが追加されたときにインターフェースとその下のすべてのサブクラスを変更する必要があるため、新しい振る舞いを追加するのが面倒になることです。

特徴
  • この目的のために特別に複数の新しいクラスを導入することなく、クラス内から製品ファミリーに関連する複数のレベルの製品を共同管理することが可能です。
  • 新しい製品ファミリーが追加されても、元のコードを変更する必要はなく、オープン・クローズの原則を満たすことができます。
  • 欠点は、新しい製品を製品ファミリーに追加する必要がある場合、すべてのファクトリークラスを変更する必要があることです。
Abstractファクトリー・パターンのキーパーソン :
  • 抽象ファクトリ: 製品を作成するためのインターフェイスを提供し、異なるレベルの複数の製品を作成するためのいくつかのメソッド new Product() を含みます。
  • 具体的なファクトリー:主に抽象ファクトリーでいくつかの抽象メソッドを実装し、具体的な製品の作成を完了します。
  • 抽象製品: 製品の仕様を定義し、製品の主な機能と特徴を記述します。抽象ファクトリー・パターンには複数の抽象製品があります。
  • 具象製品:抽象製品ロールによって定義されたインターフェースを実装し、具象ファクトリーによって作成されます。
クラス図の分析
コード

抽象ファクトリーパターンの抽象化レイヤー

package.ppdxzz.abstractfactory;
/**
 * Description:Abstract Factoryパターンの抽象化のトップレベル
 * 
 */
public interface AbstractFactory {
 //グラフィックを作成するメソッドを定義し、そのサブクラスに実装させる。
 Graph createGraph(String createType);
}

小湾ドローイングの工場サブクラス

package.ppdxzz.abstractfactory;
/**
 * Description:コバンのドローイングのファクトリーサブクラス
 * 
 */
public class WanFactory implements AbstractFactory{
 @Override
 public Graph createGraph(String createType) {
 Graph graph = null;
 if ("circle".equals(createType)) {
 graph = new WanCircle();
 }else if ("rectangle".equals(createType)) {
 graph = new WanRectangle();
 }
 return graph;
 }
}

シャオリーのドローイングのファクトリーサブクラス

package.ppdxzz.abstractfactory;
/**
 * Description:Liのドローイングのファクトリーサブクラス
 * 
 */
public class LiFactory implements AbstractFactory {
 @Override
 public Graph createGraph(String createType) {
 Graph graph = null;
 if ("circle".equals(createType)) {
 graph = new LiCircle();
 }else if ("rectangle".equals(createType)) {
 graph = new LiRectangle();
 }
 return graph;
 }
}

グラフィックス抽象クラス

package.ppdxzz.abstractfactory;
/**
 * Description:グラフィックスの抽象クラス
 * 
 */
public abstract class Graph {
 //描画を開始する
 public abstract void startDraw();
 //描画を終了する
 public abstract void finishDraw();
}

シャオワンのサークル・ドローイングの具体的な実施方法

package.ppdxzz.abstractfactory;
/**
 * Description:ワンダは円を描く
 * 
 */
public class WanCircle extends Graph {
 @Override
 public void startDraw() {
 System.out.println("ワンダは円を描き始める。...");
 }
 @Override
 public void finishDraw() {
 System.out.println("ワンダは円を描いて終わる...");
 System.out.println("-------------------");
 }
 
}

シャオ・リのドローイング矩形の具体的な実装

package.ppdxzz.abstractfactory;
/**
 * Description:Liは矩形を描く
 * 
 */
public class LiRectangle extends Graph {
 @Override
 public void startDraw() {
 System.out.println("Leeは矩形を描き始める。...");
 }
 @Override
 public void finishDraw() {
 System.out.println("Leeは矩形を描き終える...");
 System.out.println("-------------------");
 }
}

製図のためのツールキット

package.ppdxzz.abstractfactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * Description:描画のためのツールクラス
 * 
 */
public class DrawGraph {
 AbstractFactory factory;
 //コンストラクタのメソッド
 public DrawGraph(AbstractFactory factory) {
 setFactory(factory);
 }
 private void setFactory(AbstractFactory factory) {
 Graph graph = null;
 String createType = "";
 this.factory = factory;
 do {
 createType = getType();
 //factoryWanのファクトリーサブクラスであったり、Liのファクトリーサブクラスであったりする。
 graph = factory.createGraph(createType);
 if (graph != null) {
 graph.startDraw();
 graph.finishDraw();
 }else {
 System.out.println("入力エラー、終了しました!");
 break;
 }
 }while (true);
 }
 //ドラフターが描いたグラフィックの形状を取得する
 private String getType() {
 try {
 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 System.out.println("描画するグラフィックの形状を入力してください: ");
 String str = reader.readLine();
 return str;
 } catch (IOException e) {
 e.printStackTrace();
 return "";
 }
 }
}

グラフィックの特定の引き出し

package.ppdxzz.abstractfactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * Description:グラフィックスドロワー
 * 
 */
public class DrawPerson {
 public static void main(String[] args) {
 System.out.println("引き出しの名前を入力してください: ");
 try {
 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 String name = reader.readLine();
 if ("xw".equals(name)) {
 new DrawGraph(new WanFactory());
 }else {
 new DrawGraph(new LiFactory());
 }
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
}

デモ:

JDKソースコードの解析:
まとめ
  • Abstractファクトリーパターンの拡張には、ある種の「開閉原理」の偏りがあります。

    • 新しい製品ファミリを追加するだけで、新しい特定の工場を追加する必要がある場合は、オープンとクローズの原則を満たすために、元のコードを変更する必要はありません;

    • 新しいタイプの製品を製品ファミリーに追加する必要がある場合、すべてのファクトリークラスを変更する必要があり、開閉の原則を満たしていません。

  • 一方、システム内に階層構造化された製品が1つしかない場合、Abstract FactoryパターンはFactory Methodパターンに劣化します。

  • 設計レベルでは、Abstract FactoryパターンはSimple Factoryパターンを改良したものです。

  • ファクトリーは、抽象ファクトリーとファクトリーサブクラスの具体的な実装の2つの層に抽象化されています。プログラマは、作成するオブジェクトのタイプに応じて対応するファクトリーのサブクラスを使用できます。これにより、単一の単純なファクトリクラスがファクトリのクラスタになり、メンテナンスや拡張が容易になります。

抽象ファクトリーパターンは以上です。 次のデザインパターンはビルダーパターンです。

Read next

ファイルの断片化がフラッシュのパフォーマンスに与える影響

この記事では、ファイルの断片化がフラッシュのパフォーマンスに与える影響に焦点を当てます。 この記事を読む前に、以下の2つの記事「NANDフラッシュの基礎入門」と「フラッシュの書き込み性能低下の問題」を読むことをお勧めします。 前回の記事では、フラッシュ内部の2つの概念であるブロックとページを紹介しました。 今回の記事では、 ...

May 4, 2020 · 2 min read