回答:
DIとStrategyは同じように機能しますが、Strategyは、よりきめ細かく短期間の依存関係に使用されます。
オブジェクトが「固定」戦略で構成されている場合、たとえばオブジェクトが構築されている場合、戦略とDIの違いは不鮮明です。ただし、DIシナリオでは、オブジェクトのライフタイム中にオブジェクトの依存関係が変化することはまれですが、これはストラテジーでは珍しいことではありません。
また、メソッドに引数として戦略を渡すことができますが、メソッド引数注入の関連する概念は広く普及しておらず、自動テストのコンテキストでのみ主に使用されています。
戦略は意図に焦点を当てており、同じ動作規約に従うさまざまな実装を持つインターフェースを作成することをお勧めします。DIは、いくつかの動作を実装し、それを提供することに関するものです。
DIを使用すると、実装の一部を交換できる以外の理由でプログラムを分解できます。実装が1つだけのDIで使用されるインターフェイスは非常に一般的です。(常に)1つの具体的な実装のみを持つ「戦略」は、実際の問題ではありませんが、おそらくDIに近いでしょう。
in a DI scenario it is more unusual that the dependencies of objects change during their lifetimes, while this is not uncommon with Strategy
違いは、彼らが達成しようとしていることです。Strategyパターンは、実装を交換したい場合に使用されます。例として、さまざまな方法でデータをフォーマットしたい場合があります。戦略パターンを使用して、XMLフォーマッターやCSVフォーマッターなどを交換できます。
依存性注入は、ユーザーが実行時の動作を変更しようとしていないという点で異なります。上記の例に従って、XMLフォーマッターを使用するXMLエクスポートプログラムを作成する場合があります。次のようにコードを構造化するのではなく:
public class DataExporter() {
XMLFormatter formatter = new XMLFormatter();
}
コンストラクタにフォーマッタを「挿入」します。
public class DataExporter {
IFormatter formatter = null;
public DataExporter(IDataFormatter dataFormatter) {
this.formatter = dataFormatter;
}
}
DataExporter exporter = new DataExporter(new XMLFormatter());
Dependency Injectionにはいくつかの正当化がありますが、主な理由はテストです。ある種の永続化エンジン(データベースなど)がある場合があります。ただし、テストを繰り返し実行しているときに実際のデータベースを使用するのは面倒な場合があります。したがって、テストケースの場合は、ダミーデータベースを挿入して、オーバーヘッドが発生しないようにします。
この例を使用すると、違いを確認できます。私たちは常にデータストレージ戦略を使用することを計画しており、それが渡されるものです(実際のDBインスタンス)。ただし、開発とテストでは、さまざまな依存関係を使用する必要があるため、さまざまな具体化を注入します。
DIを戦略パターンとして使用できるので、各顧客に必要なアルゴリズムを入れ替えることができますが、DIはアプリケーションの一部ではない部分を分離する方法であるため、それを超えることができます。戦略パターン。
DIは単に戦略パターンの名前を変更しただけであり、戦略パターンの実際の目的であるIMOが希薄化し始めると言うのは危険です。
おい、依存性注入はより一般的なパターンであり、具体化ではなく抽象化への依存性に関するものであり、すべてのパターンの一部ですが、戦略パターンはより具体的な問題の解決策です
これはウィキペディアの定義です:
DI:
オブジェクト指向のコンピュータープログラミングにおける依存関係の注入(DI)は、動作を依存関係の解決から分離するという中心的な原則を持つ設計パターンです。つまり、依存度の高いソフトウェアコンポーネントを分離するための手法です。
戦略パターン:
コンピュータープログラミングでは、戦略パターン(ポリシーパターンとも呼ばれます)は特定のソフトウェア設計パターンであり、実行時にアルゴリズムを選択できます。
戦略パターンは、アルゴリズムのファミリーを定義し、それぞれをオブジェクトとしてカプセル化し、それらを交換可能にする手段を提供することを目的としています。戦略パターンにより、アルゴリズムは、アルゴリズムを使用するクライアントとは独立して変化します。
戦略は、物事の計算方法を変更するために使用される高レベルの物事です。依存性注入を使用すると、計算方法だけでなく、そこにあるものも変更できます。
私にとっては、単体テストを使用すると明らかになります。プロダクションコードの実行では、すべてのデータを非表示(つまり、プライベートまたは保護)にします。一方、単体テストでは、ほとんどのデータが公開されているため、アサートで確認できます。
戦略の例:
public class Cosine {
private CalcStrategy strat;
// Constructor - strategy passed in as a type of DI
public Cosine(CalcStrategy s) {
strat = s;
}
}
public abstract class CalcStrategy {
public double goFigure(double angle);
}
public class RadianStrategy extends CalcStrategy {
public double goFigure(double angle) {
return (...);
}
}
public class DegreeStrategy extends CalcStrategy {
public double goFigure(double angle) {
return (...);
}
}
戦略間で異なる公開データがないことに注意してください。また、別の方法もありません。どちらの戦略も、すべて同じ機能とシグネチャを共有しています。
次に、依存性注入について:
public class Cosine {
private Calc strat;
// Constructor - Dependency Injection.
public Cosine(Calc s) {
strat = s;
}
}
public class Calc {
private int numPasses = 0;
private double total = 0;
private double intermediate = 0;
public double goFigure(double angle) {
return(...);
}
public class CalcTestDouble extends Calc {
// NOTICE THE PUBLIC DATA.
public int numPasses = 0;
public double total = 0;
public double intermediate = 0;
public double goFigure(double angle) {
return (...);
}
}
使用する:
public CosineTest {
@Test
public void testGoFigure() {
// Setup
CalcTestDouble calc = new CalcTestDouble();
Cosine instance = new Cosine(calc);
// Exercise
double actualAnswer = instance.goFigure(0.0);
// Verify
double tolerance = ...;
double expectedAnswer = ...;
assertEquals("GoFigure didn't work!", expectedAnswer,
actualAnswer, tolerance);
int expectedNumPasses = ...;
assertEquals("GoFigure had wrong number passes!",
expectedNumPasses, calc.numPasses);
double expectedIntermediate = ...;
assertEquals("GoFigure had wrong intermediate values!",
expectedIntermediate, calc.intermediate, tolerance);
}
}
最後の2つのチェックに注意してください。彼らは、テスト対象のクラスに挿入されたテストダブルでパブリックデータを使用しました。データ非表示の原則により、量産コードではこれを行うことができませんでした。特別な目的のテストコードを製品コードに挿入したくありませんでした。公開データは別のクラスでなければなりませんでした。
テストダブルが注入されました。機能だけでなくデータにも影響を与えるため、これは単なる戦略とは異なります。
依存性注入は、簡単に説明する戦略パターンの改良版です。多くの場合、実行時にいくつかの代替モジュールから選択する必要があります。これらのモジュールはすべて共通のインターフェースを実装しているため、相互に交換して使用できます。戦略パターンの目的は、意思決定プロセスを戦略オブジェクトと呼ぶ個別のオブジェクトにカプセル化することで、どのモジュールを使用するか(つまり、「具体的な戦略」または依存関係)を決定する負担を取り除くことです。
依存性注入は、使用する具体的な戦略を決定するだけでなく、具体的な戦略のインスタンスを作成し、それを呼び出しモジュールに「注入」することによって、戦略パターンを洗練します。具体的な戦略インスタンスを管理する方法(初期化など)の知識も戦略オブジェクト内に隠すことができるため、依存関係が1つしかない場合でもこれは役立ちます。
戦略は、依存関係注入スキルを使用する場です。依存性注入を実装する実際の方法は次のとおりです。
ただし、戦略が際立っている点が1つあります。Unityでご存知のように、アプリケーションの起動時にすべての依存関係が設定され、それ以上変更することはできません。ただし、戦略は実行時の依存関係の変更をサポートします。しかし、私たちは戦略の責任ではなく、依存関係を管理/注入する必要があります!
実際、戦略は依存関係の注入について話していません。必要に応じて、Strategyパターン内のAbstract Factoryを介して実行できます。ストラテジーは、インターフェースを持つクラスのファミリーを作成し、それで「遊ぶ」ことについてのみ話します。プレイ中に、クラスが別の階層にあることがわかった場合は、それを自分自身で注入する必要がありますが、戦略の仕事ではありません。
SOLIDの原則を検討する場合-オープンクローズドプリンシパルにはストラテジーパターンを使用し、依存関係逆転原理には依存関係インジェクションを使用します