今日は、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つの層に抽象化されています。プログラマは、作成するオブジェクトのタイプに応じて対応するファクトリーのサブクラスを使用できます。これにより、単一の単純なファクトリクラスがファクトリのクラスタになり、メンテナンスや拡張が容易になります。
抽象ファクトリーパターンは以上です。 次のデザインパターンはビルダーパターンです。