私は、依存性注入具体的には、最近のデザインパターンについて多くのことを学んできました。私は、抽象factorysは、依存関係を持つオブジェクトをインスタンス化する良い方法であることを確信しています。しかし、私は彼らが使用することになっているものを工場下位レベルのオブジェクトに伝えるかどうかはわかりません。
以下の簡単な例を考えてみましょう。
私は抽象的な工場でIGeneticAlgorithmをインスタンス化したい、実行中のある時点で、クラスのメインプログラムを(私はちょうど私のプログラム内の他のコードがあることを表すためにこれを作った。)があります。
public class MainProgram{
private AbstractGeneticAlgorithm geneticAlgorithm;
private IGeneticAlgorithmFactory geneticAlgorithmFactory;
public MainProgram(IGeneticAlgorithmFactory geneticAlgorithmFactory){
this.geneticAlgorithmFactory = geneticAlgorithmFactory;
}
private void makeGeneticAlgorithm(){
geneticAlgorithm = geneticAlgorithmFactory.getInstance();
}
public static void main(String[] args){
MainProgram mainProgramm = new MainProgram(new FastGeneticAlgorithmFactory());
//...
}
}
public interface IGeneticAlgorithmFactory{
public IGeneticAlgorithm getInstance();
}
public class FastGeneticAlgorithmFactory implements IGeneticAlgorithmFactory{
public IGeneticAlgorithm getInstance(){
return new FastGeneticAlgorithm();
}
}
public abstract class AbstractGeneticAlgorithm{
private IIndividual individual;
private IIndividualFactory individualFactory;
private void makeIndividual(){
individual = individualFactory.getInstance();
}
//...
}
実行中のある時点で私は私のGeneticAlgorithmでIIndividualをインスタンス化します。IIndividualは、起動時にインスタンス化することはできません。実行時にIIndividualをインスタンス化することができるようにする必要性は、基本的には、選択-組換え変異の各ステップの後に新しい個人をインスタンス化する必要が道遺伝的アルゴリズムの仕事、から来ています。(詳細については、参照https://en.wikipedia.org/wiki/Genetic_algorithm)。私はこの例をシンプルに保つために、ここでAbstractGeneticAlgorithm一つだけIIndividualを与えることを選びました。
public class FastGeneticAlgorithm implements AbstractGeneticAlgorithm{
private IIndividual individual;
private IIndividualFactory individualFactory;
}
public interface IIndividualFactory{
public IIndividual getInstance();
}
public class SmallIndividualFactory implements IIndividualFactory{
public IIndividual getInstance(){
return new SmallIndividual();
}
//...
}
public interface IIndividual{
//...
}
public class SmallIndividual implements IIndividual{
//...
}
SmallIndividualFactory FastGeneticAlgorithmでの静的変数作ることは良い練習のように私には思えません。メインにSmallIndividualFactoryを渡し、その主なFastGeneticAlgorithmにそれを渡すことができるということもないと思えます。
私の質問はこれを解決する方法ですか?ありがとうございました。
それは依存性注入を使用することになると、Abstract Factoryパターンは、多くの場合、過剰に使用されます。これは、それ自体は悪いパターンだという意味ではありませんが、多くの場合、Abstract Factoryパターンのためのより適切な選択肢があります。これは、中に詳細に記載されている依存性注入の原則、プラクティス、およびパターン(パラグラフ6.2と記載されています):
- 抽象工場は、依存の消費者がその生涯を忘れなければならないので、短命、ステートフルな依存関係を作成するために使用すべきではありません。消費者の視点から、概念的サービスの唯一のインスタンスが存在すべきです。
- 抽象化の消費者がそのを決定すべきであることを意味し、「抄録を上/政策層によって所有されている」:DIP状態ながら、彼らのデザインは、多くの場合、消費者に合っていないため、抽象工場は、多くの場合、依存関係逆転の原則(DIP)違反ですそのが最も必要とする訴訟という形で抽象化した形状と定義します。消費者まかせ工場の依存関係と、それは消費者が複雑に生成し、依存関係の両方に依存します。
この意味は:
- それは短命さ依存性を意味し、その寿命は、消費者によって制御されているので、パラメータなしで抽象工場では、この方法を防止する必要があります作成します。代わりに、抽象工場を概念的に作成する(消費者により提供される)ランタイムデータを必要とする依存関係を作成する必要があります。
- しかし、たとえファクトリメソッドにパラメータが含まれている場合には、注意が抽象ファクトリーが本当に必要とされていることを確認するために注意する必要があります。それは代わりに、工場とその製品の両方に依存のため、消費者は単一の依存関係を持つことができますので、プロキシパターンは、しばしば(常にではない)適しています。
依存性の注入は、アプリケーションの起動パス内のクラスの構成を促進し、コンセプトブックは、などを指し作曲ルート。作曲ルートは、そのアプリケーションのエントリポイント(あなたの場所の近くにあるMain
メソッド)とは、システム内の他のすべてのモジュールについて知っています。
コンポジションのルートは、システム内の他のすべてのモジュールへの依存性がかかるので、それは一般的にほとんど意味が作曲ルート内の抽象工場を消費します。例えば、場合にあなたが定義されたIXFactory
農産物に抽象化しIX
、依存関係が、作曲ルートが唯一の消費者であるIXFactory
抽象化、あなたはデカップリングを必要としない何かをデカップリングされている:合成ルートは、本質的にシステムの他のすべての部分について知っているどのような方法を。
これはあなたのケースであるように思わIGeneticAlgorithmFactory
抽象化。その唯一の消費者は、自分の作曲ルートのようです。これが真である場合、この抽象化とその実装は単純に除去することができ、その内のコードgetInstance
方法は、単純に移動することができるMainProgram
クラス(コンポジションのルートとして機能します)。
私はあなたのかどうかを理解することが難しいIIndividual
の実装が(それは私が大学で遺伝的アルゴリズムを実装するので、少なくとも14年前にされている)の工場が必要ですが、彼らはより多くのランタイムデータではなく、「本当の」依存関係のように見えます。彼らの作成と実装は、抽象化の後ろに隠されなければならないかどうかを確認んがそう工場は、ここでは意味をなさないかもしれません。とき、私は、アプリケーションが十分に疎結合することが想像できるFastGeneticAlgorithm
作成しSmallIndividual
、直接インスタンスを。これは、しかし、ちょうど野生の推測です。
その上で、最善の方法は、コンストラクタ・インジェクションを適用することです。これは防ぎ時間的カップリングを。さらに、あなたのように、定義された抽象化で実装依存関係を指定控えAbstractGeneticAlgorithm
行います。これは抽象化になり漏れの抽象化(DIP違反です)。代わりに、(実装上のコンストラクタの引数としてそれらを宣言することで、依存関係を宣言しFastGeneticAlgorithm
、あなたの場合)。
しかし、たとえの存在をIIndividualFactory
以下のように、あなたのコードは、次のベストプラクティスによって簡素化することができます。
// Use interfaces rather than base classes. Prefer Composition over Inheritance.
public interface IGeneticAlgorithm { ... }
public interface IIndividual { ... }
public interface IIndividualFactory {
public IIndividual getInstance();
}
// Implementations
public class FastGeneticAlgorithm implements IGeneticAlgorithm {
private IIndividualFactory individualFactory;
// Use constructor injection to declare the implementation's dependencies
public FastGeneticAlgorithm(IIndividualFactory individualFactory) {
this.individualFactory = individualFactory;
}
}
public class SmallIndividual implements IIndividual { }
public class SmallIndividualFactory implements IIndividualFactory {
public IIndividual getInstance() {
return new SmallIndividual();
}
}
public static class Program {
public static void main(String[] args){
AbstractGeneticAlgorithm algoritm = CreateAlgorithm();
algoritm.makeIndividual();
}
private AbstractGeneticAlgorithm CreateAlgorithm() {
// Build complete object graph inside the Composition Root
return new FastGeneticAlgorithm(new SmallIndividualFactory());
}
}