回答:
抽象ファクトリは、依存性注入(DI)の非常に中心的な設計パターンです。以下は、抽象ファクトリの適用がソリューションとして受け入れられたスタックオーバーフローの質問のリストです。
私の理解の及ぶ限り、これらの質問は人々が抱えていた実際の懸念や問題を表しています。そのため、実際の例から始めることができます。
Abstract Factoryパターンの実際の使用例は、2つの異なるデータソースへのデータアクセスを提供することです。アプリケーションがさまざまなデータストアをサポートしているとします。(例:SQLデータベースとXMLファイル)。2つの異なるデータアクセスインターフェイスがあります。たとえば、IReadableStore
およびIWritableStore
は、使用するデータソースのタイプに関係なく、アプリケーションが期待する一般的なメソッドを定義します。
使用するデータソースのタイプによって、クライアントコードがデータアクセスクラスを取得する方法が変わることはありません。あなたは、AbstractDataAccessFactory
データソースの種類が設定されているかを知っているし、提供し、具体的な工場をクライアントコードのために、すなわちSqlDataAccessFactory
かXmlDataAccessFactory
。これらの具体的な工場は、例えば、具体的な実装を作成することができますSqlReadableStore
し、SqlWriteableStore
。
.NET Framework のDbProviderFactoryは、このパターンの例です。
私があなたを正しく理解しているなら-問題は、なぜFactoryメソッドと抽象的なファクトリパターンの両方があるのかということです。異なるポリモーフィッククラスのインスタンス化手順が異なる場合は、抽象ファクトリが必要です。また、オブジェクトの初期化の詳細を知らなくても、いくつかのモジュールでインスタンスを作成して使用したいとします。たとえば、いくつかの計算を行うJavaオブジェクトを作成するとします。ただし、一部はアプリケーションの一部ですが、他のバイトコードはDBから読み取る必要があります。一方、なぜファクトリメソッドが必要なのですか?同意します、その抽象的なファクトリはそれに重なります。しかし、場合によっては、コードの記述がはるかに少なく、クラスやインターフェースが少ないため、システムを理解しやすくなります。
具象クラス自体のオブジェクトを作成することでタスクを達成できるため、抽象ファクトリパターンの使用方法は何ですか。Concreteクラスのオブジェクトを作成するファクトリメソッドがあるのはなぜですか?
Abstract Factoryがない場合、クライアントは具象クラスの詳細を知る必要があります。この密結合はAbstract Factoryで削除されました。
これで、ファクトリメソッドは、クライアントが使用する必要があるコントラクトを公開します。Factoryメソッドによって公開されるインターフェースを実装する新製品を追加することにより、より多くの製品を工場に追加できます。
理解を深めるには、関連するSEの質問を参照してください。
ファクトリパターンと抽象ファクトリパターンの基本的な違いは何ですか?
意図:
具体的クラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリを作成するためのインターフェースを提供します。
これから、抽象ファクトリパターンの意図、構造、チェックリスト、および経験則を理解できます。ソース作成記事ます。
チェックリスト:
抽象ファクトリは、コードベースを統一したまま、複数のプラットフォームをサポートするのに最適です。Windows、Linux、OSXで実行したい大きなQtまたはGTK +または.NET / Monoプログラムがあるとします。しかし、各プラットフォームで異なる方法で実装されている機能があります(おそらく、kernel32 APIまたはPOSIX機能を介して)。
public abstract class Feature
{
public abstract int PlatformSpecificValue { get; }
public static Feature PlatformFeature
{
get
{
string platform;
// do platform detection here
if (platform == "Win32")
return new Win32Feature();
if (platform == "POSIX")
return new POSIXFeature();
}
}
// platform overrides omitted
}
この抽象ファクトリーを使用すると、UIは現在のプラットフォームについて何も知る必要がありません。
Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
抽象化で機能するコードがあることを簡単に想像できます。具象クラスではなく抽象化を作成する必要があります。
コードをより適切に変更できるため、常に抽象化に反対する必要があります。
これは良い例です:http : //en.wikipedia.org/wiki/Abstract_factory_pattern#C.23
Abstract Factoryパターンが過大評価されていることに気づきました。
まず第一に、起こらないことをあなたが設定していることが多い相互にインスタンス化するタイプを。
第二に、インターフェースによって提供される間接性(抽象化)のレベル通常、依存関係注入を処理するときに十分です。
WindowsButton、MacButton、WindowsScrollBar、MacScrollbarなどがあるWindowsGui vs MacGui vs ...の典型的な例は、ビジターやインタープリターパターンを使用して具体的なボタンやスクロールバーなどを定義することで実装が簡単になることがよくあります。実際の行動。
インスタンス化が非常に複雑で、1つのファクトリでは複雑で見苦しく、UIで理解するには複雑すぎる場所には、単純なファクトリパターンではなく、抽象的なファクトリパターンの場所があると思います。
これが単一クラスではなくTYPE_Aブランドであるとします。たとえば、Type-Aの100種類の類似クラスのファミリーがあり、それらから1つのオブジェクトをインスタンス化する必要があるとします。多くの類似したタイプのオブジェクトのブランドから正しいオブジェクトを作成するために必要な詳細で洗練された情報があり、このオブジェクトエンティティでは、調整するパラメーターとそれらを調整する方法を正確に知る必要があると想像してください。
このブランドの特別な工場では、それらを区別し、インスタンス化する正確なオブジェクトと、インスタンス化の方法を取得します。ネットからの入力(オンラインストアで利用できる色としましょう)や、バックグラウンドで実行されている他のアプリケーションやサービスからの入力(UIでは認識されないパラメーター)がわかります。
そして、たぶん明日は、インスタンス化するtype_Bとtype_Cのような別のファミリがあるでしょう。したがって、UIには「if else」があり、ユーザーが「type_A」、「type_B」、または「type_C」を必要とするかどうかがわかります。ただし、ファクトリークラスは、タイプ(ファミリー)からビルドするクラスを正確に決定します。チューニング方法–パラメータに設定する値、または請負業者に送信する値。このすべて-UIが認識していない多くのパラメーターによる。これらすべては、単一のファクトリークラスには多すぎます。
あなたが.jarを作成し、他の誰かがそのjarを使用していて、コードで新しい具象オブジェクトを使用したいとします。抽象ファクトリを使用していない場合、彼女はあなたのコードを変更するか、コードを上書きする必要があります。しかし、抽象ファクトリを使用している場合は、ファクトリを提供してコードに渡すことができ、すべてが問題ありません。
洗練されたバージョン:以下のシナリオを検討してください:誰かがフレームワークを書きました。フレームワークは、抽象ファクトリといくつかの具体的なファクトリを使用して、実行時に多くのオブジェクトを作成します。したがって、独自のファクトリを既存のフレームワークに簡単に登録し、独自のオブジェクトを作成できます。フレームワークは変更に近づいていますが、抽象的なファクトリパターンにより、拡張は簡単です。
このパターンは、クライアントが作成するタイプを正確に知らない場合に特に役立ちます。例として、携帯電話を独占的に販売しているショールームがサムスン製のスマートフォンのクエリを取得するとします。ここでは、作成されるオブジェクトの正確なタイプがわかりません(電話のすべての情報が具体的なオブジェクトの形式でラップされていると想定しています)。しかし、私たちはサムスン製のスマートフォンを探していることを知っています。この情報は、設計に抽象ファクトリ実装がある場合に実際に利用できます。
実際の例は、DbConnection、DbCommand、およびDbDataAdapterを含む抽象基本クラスを持ち、System.Data.SqlClientやSystem.Data.OracleClientなどの.NET Frameworkデータプロバイダーによって共有されるSystem.Data.Common名前空間で提供されます。開発者が特定のデータプロバイダーに依存しない一般的なデータアクセスコードを記述できるようにします。
DbProviderFactoriesクラスは、DbProviderFactoryインスタンスを作成するための静的メソッドを提供します。次に、インスタンスは、プロバイダー情報と実行時に提供される接続文字列に基づいて、厳密に型指定された正しいオブジェクトを返します。
例:
DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();
/* Getting SqlClient family members */
DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbCommand dbCommand = dbProviderFactory.CreateCommand();
DbConnection dbConnection = dbProviderFactory.CreateConnection();
DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();
SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
SqlConnection sqlConnection = (SqlConnection)dbConnection;
SqlCommand sqlCommand = (SqlCommand) dbCommand;
SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;
/* Getting OracleClient family members*/
dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
dbCommand = dbProviderFactory.CreateCommand();
dbConnection = dbProviderFactory.CreateConnection();
dbDataAdapter = dbProviderFactory.CreateDataAdapter();
OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
OracleConnection oracleConnection = (OracleConnection)dbConnection;
OracleCommand oracleCommand = (OracleCommand)dbCommand;
OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;
コンクリートファクトリインスタンスは、以下のように静的ファクトリメソッドを使用して提供されます
public class FurnitureProviderFactory
{
public static IFurnitureFactory GetFactory(string furnitureType)
{
if (furnitureType == "Wood")
{
return new WoodenFurnitureFactory();
}
if (furnitureType == "Plastic")
{
return new PlasticFurnitureFactory();
}
throw new Exception("Undefined Furniture");
}
}