Abstract Factory パターンは次のように定義されます。
1. 目的:特定のクラスを指定せずに、一連の関連オブジェクトまたは相互依存オブジェクトを作成するためのインターフェイスを提供します。
(具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリーを作成するためのインターフェイスを提供します。)
2. 参加者: (5 つの役割)
• Abstract Factory (AbstractFactory):抽象製品オブジェクトを作成するための操作インターフェイスを宣言します。
• ConcreteFactory:特定の製品オブジェクトを作成する操作を実装します。
• Abstract Product:あるタイプの製品オブジェクトのインターフェイスを宣言します。
•コンクリート製品 (ConcreteProdcut):対応するコンクリート ファクトリによって作成される製品オブジェクトを定義します。AbstractProductインターフェイスを実装します。
•クライアント: AbstractFactoryクラスとAbstractProductクラスによって宣言されたインターフェイスのみを使用します。
最初にclientの役割を見たとき、私は少し混乱しましたが、クライアントは抽象ファクトリー パターンでどのような役割を果たしているのでしょうか?
以前「シンプル・ファクトリ・パターン」や「ファクトリ・メソッド・パターン」を学習したときに書いた例(1~7)のクライアント(Customer)と同じ意味でしょうか?もしそうなら、ファクトリ メソッド パターンにクライアント参加者が存在しないのはなぜですか?
GOF デザイン パターンには参加者「クライアント」が含まれていますが、Yan Hon の「Java とパターン」には参加者「クライアント」が含まれていません。
その後、クライアントは抽象ファクトリを使用して抽象製品をアセンブルし、抽象ファクトリ パターンを使用してクライアントに呼び出しインターフェイスを提供する必要があることが理解されたようです。以下の例 8でクライアントの役割を理解します。
実際、多くの例では、クライアントは抽象ファクトリーにマージされ、一部はクライアントにマージされます。
3. 構造:
図1:GoFのデザインパターン内(以下のような形式)
図 2: Yan Hon の「Java とパターン」内 (以下のフォームと同様)
抽象的なファクトリ パターンを見たとき、私は常にそれをファクトリ メソッド パターンと比較します。
どちらのモードにも同じ 4 つの文字があります。
抽象ファクトリー (AbstractFactory) ---> 具体ファクトリー (ConcreteFactory)
抽象的なプロダクト (AbstractProduct) ---> 具体的なプロダクト (ConcreteProdcut)
では、これら 2 つのモードの違いは何でしょうか?
意図の違いを見てください。
1. ファクトリ メソッド パターン:オブジェクトを作成するためのインターフェイスを定義し、どのクラスをインスタンス化するかをサブクラスに決定させます。ファクトリ メソッドは、クラスのインスタンス化をそのサブクラスに延期します。
(オブジェクトを作成するためのインターフェイスを定義しますが、どのクラスをインスタンス化するかをサブクラスに決定させます。ファクトリ メソッドにより、クラスはインスタンス化をサブクラスに延期できます。)
2. Abstract Factory Pattern :特定のクラスを指定せずに、一連の関連オブジェクトまたは相互依存オブジェクトを作成するためのインターフェイスを提供します。
(具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリーを作成するためのインターフェイスを提供します。)
これら 2 つのモードの意図を通して、次のことがわかります。
1. ファクトリ メソッド パターンは、製品オブジェクトの作成に使用されます。つまり、各抽象ファクトリは抽象製品オブジェクトの作成に使用され、その抽象ファクトリを継承する各具象ファクトリは、特定の製品オブジェクトの作成に使用されます。
2. 抽象ファクトリ パターンは、複数 (セットまたはシリーズ)の製品オブジェクトを作成するために使用されます。つまり、各抽象ファクトリは、複数 (セットまたはシリーズ) の抽象製品オブジェクトを作成するために使用され、その抽象ファクトリを継承します。各コンクリート ファクトリを使用して、複数 (セットまたはシリーズ)のコンクリート製品オブジェクトを作成できます。
では、引き続き「クルマづくり」を例に挙げると、
1. ファクトリメソッドモードでは、各車は製品オブジェクトです(エンジン、ドアなどの自動車部品は車の属性とみなされます)。
工場で自動車を生産するプロセスは、実際には自動車の部品を組み立てるプロセスにすぎません。
2. 抽象ファクトリー モードでは、各車は一連の自動車部品製品オブジェクトで構成されます(エンジン、ドアなどはすべて製品であり、属性ではありません)。
工場で自動車を生産するプロセスは、最初に個々の自動車部品を生産し、次に自動車部品を組み立てるプロセスになりました。
Yan Hon 氏は「JAVA とパターン」で次のように述べています。
抽象ファクトリ パターンとファクトリ メソッド パターンの最大の違いは、ファクトリ メソッド パターンが製品レベルの構造を対象としているのに対し、抽象ファクトリ パターンは複数の製品レベルの構造に対応する必要があることです。
「製品階層」という用語は抽象的に感じられます。
1. 製品階層とは何ですか?
アウディ A6、アウディ A8、さらには BMW X6 もすべて車であるため、製品クラスとみなすことができます。
赤い Audi A6、黒い Audi A8、さらには BMW もすべて車であるため、製品クラスとみなすことができます。
画像3:
上記の各車のエンジン、アウディ A6 エンジンとアウディ A8 エンジン (ここではエンジン型式が異なるものとします) もすべてエンジンであるため、製品レベルとみなすことができます。
図4:
2. 複数の製品レベルの組織とは何ですか?
Audi A6 のエンジン、Audi A6 のドア、Audi A6 のタイヤは、異なる種類の製品であるため、複数の製品レベルで構成されています。
つまり、エンジン、ドア、タイヤなどの自動車部品は、それぞれが製品の一種を表しており、継承や実装の関係はなく、交差することもありません。
それらの間には並列関係がありますが、組み合わせると 1 つの自動車 (製品ファミリー) を形成できます。
Audi A6 車は、一連の Audi A6 エンジン、Audi A6 ドア、Audi A6 タイヤ、およびその他の自動車部品製品を組み合わせたものです。
図5:
Abstract Factory パターンの例と Java 実装:
顧客が一汽フォルクスワーゲン車の購入を希望する場合、車のエンジンと車体も対応するモデルでなければなりません。
顧客 A は Audi A6 を購入したいと考えており、顧客 A は Audi A8 を購入したいと考えています。例 8:
自動車エンジン (抽象製品):
/*
* 汽车发动机(抽象产品)
*/
public interface Engine {
}
アウディ A6 エンジン (特定の製品):
/*
* 奥迪A6的发动机(具体产品)
*/
public class AudiA6Engine implements Engine{
public String toString(){
return "奥迪A6发动机";
}
}
アウディ A8 エンジン (特定の製品):
/*
* 奥迪A8的发动机(具体产品)
*/
public class AudiA8Engine implements Engine{
public String toString(){
return "奥迪A8发动机";
}
}
車体(抽象製品):
/*
* 汽车车身(抽象产品)
*/
public interface CarBody {
}
アウディ A6 ボディ (特定の製品):
/*
* 奥迪A6的车身(具体产品)
*/
public class AudiA6CarBody implements CarBody {
public String toString(){
return "奥迪A6车身";
}
}
アウディ A8 ボディ (特定の製品):
/*
* 奥迪A8的车身(具体产品)
*/
public class AudiA8CarBody implements CarBody {
public String toString(){
return "奥迪A8车身";
}
}
一汽フォルクスワーゲン工場 (抽象工場):
/*
* 一汽大众工厂(抽象工厂)
*/
public interface CarFactory {
/*
* 生产汽车发动机的工厂方法(创建一种产品对象)
*/
public Engine createEngine();
/*
* 生产汽车车身的工厂方法(创建另一种产品对象)
*/
public CarBody createCarBody();
}
アウディA6工場(特定工場):
/*
* 奥迪A6工厂(具体工厂)
*/
public class AudiA6CarFactory implements CarFactory {
/*
* 生产奥迪A6发动机的工厂方法(创建一种具体产品对象)
*/
public CarBody createCarBody() {
return new AudiA6CarBody();
}
/*
* 生产奥迪A6车身的工厂方法(创建另一种具体产品对象)
*/
public Engine createEngine() {
return new AudiA6Engine();
}
}
アウディA8工場(特定工場):
/*
* 奥迪A8工厂(具体工厂)
*/
public class AudiA8CarFactory implements CarFactory {
/*
* 生产奥迪A6发动机的工厂方法(创建一种具体产品对象)
*/
public CarBody createCarBody() {
return new AudiA8CarBody();
}
/*
* 生产奥迪A6车身的工厂方法(创建另一种具体产品对象)
*/
public Engine createEngine() {
return new AudiA8Engine();
}
}
自動 (クライアント):
自動車は実際には製品ファミリー、つまり自動車部品製品 (製品ファミリー) のセット (シリーズ) です。
ここでは Car クラスが定義されています。これは、抽象ファクトリー(CarFactory)と抽象プロダクト ( Engine、CarBody )のみを使用し、特定のファクトリー ( AudiA6CarFactory、AudiA8CarFactory )および特定のプロダクト ( AudiA6Engine、AudiA8Engine、AudiA6CarBody、AudiA8CarBody )には関与しません。
/*
* 汽车(客户端)
* 通过生产发动机的工厂和生产车身的工厂,生产汽车发动机和汽车车身,
* 最终,汽车由一套产品族(一套汽车零部件)组成。
*/
public class Car {
private CarBody body;
private Engine engine;
public Car(CarFactory carFactory){
this.body = carFactory.createCarBody();
this.engine = carFactory.createEngine();
}
public String toString(){
return "[" + this.body+"/" + this.engine + "]";
}
}
クライアント呼び出し (テスト用):
抽象ファクトリ パターンを呼び出す場合、Car クラスのコンストラクター対応の受信パラメータの型が抽象ファクトリであるため、クライアント (クライアント) ロール Carが使用されます。
このようにして、必要に応じて、目的の特定のファクトリー オブジェクト ( AudiA6CarFactory)を渡す限り、目的の製品ファミリー(adioA6Car)オブジェクトを取得できます。
別の製品ファミリー(adioA8Car)オブジェクトを取得したい場合は、別の特定のファクトリー オブジェクト(AudiA8CarFactory)を渡すだけです。
/*
* 使用抽象工厂的客户端(用于测试)
*/
public class Customers {
public static void main(String[] args){
// 创建一个奥迪A6生产工厂(具体工厂对象)
CarFactory adioA6CarFactory = new AudiA6CarFactory();
// 顾客A购买了奥迪A6(具体工厂对象作为参数,将会被用来创建汽车对象(包含了一系列相关的汽车部件产品对象))
Car adioA6Car = new Car(adioA6CarFactory);
System.out.println("顾客A买了一辆汽车" + adioA6Car);
// 创建一个奥迪A8生产工厂(具体工厂对象)
CarFactory adioA8CarFactory = new AudiA8CarFactory();
// 顾客B购买了奥迪A8(具体工厂对象作为参数,将会被用来创建汽车对象(包含了一系列相关的汽车部件产品对象))
Car adioA8Car = new Car(adioA8CarFactory);
System.out.println("顾客B买了一辆汽车" + adioA8Car);
}
}
操作結果:
顾客A买了一辆汽车[奥迪A6车身/奥迪A6发动机]
顾客B买了一辆汽车[奥迪A8车身/奥迪A8发动机]
この例の構造図:
簡単にまとめると、ファクトリ メソッド パターンを比較することで、抽象ファクトリ パターンの利点を理解できます。
1. 意図的な比較により、
抽象ファクトリ パターンを使用する目的---一連の関連または相互依存する (複数または複数のカテゴリ) オブジェクトを作成すること。
ファクトリ メソッド パターンを使用する目的は、オブジェクト (1 つまたはクラス) を作成することです。
2. 構造比較により、
抽象ファクトリー パターンでは複数の関連製品オブジェクトを作成するため、作成された製品ファミリーを統合するためにクライアント (Client)ロールが追加されます。
同時に、抽象工場パターンの工場は、任意の製品の工場ではなく、複数の製品の工場です。おそらくこれが、抽象ファクトリーパターンファクトリーが「抽象」ファクトリーと呼ばれる理由であると思います。つまり、その「抽象化」は複数の製品の「抽象化」です。
多くのマテリアルや実際のアプリケーションでは、構成ファイルとリフレクションを組み合わせることで、抽象ファクトリー パターンの利点のほとんどが完全に反映されます。
以下のリンクは、ブロガーが.NETを使って解説した抽象的なファクトリパターンで、分かりやすく、実用上非常に参考になると思います。
.NETデザインパターン(3):Abstract Factoryパターン(Abstract Factory)