戦略パターンと依存性注入の両方により、実行時にオブジェクトを設定/注入できます。戦略パターンと依存性注入の違いは何ですか?
9 に答える
DI と Strategy は同じように機能しますが、Strategy はよりきめ細かく、短期間の依存関係に使用されます。
オブジェクトが「固定された」戦略で構成されている場合、たとえばオブジェクトが構築されている場合、戦略と DI の区別が曖昧になります。しかし、DI シナリオでは、オブジェクトの依存関係が存続期間中に変化することはより珍しいことですが、これは戦略では珍しいことではありません。
また、ストラテジーを引数としてメソッドに渡すこともできますが、関連するメソッド引数インジェクションの概念は広く普及しておらず、主に自動テストのコンテキストでのみ使用されています。
戦略は意図に焦点を当て、同じ動作契約に従うさまざまな実装とのインターフェイスを作成することをお勧めします。DI とは、何らかの動作を実装して提供することです。
DI を使用すると、実装の一部を交換するだけでなく、他の理由でプログラムを分解できます。実装が 1 つだけの DI で使用されるインターフェイスは非常に一般的です。具体的な実装が 1 つしかない「戦略」は、実際の問題ではありませんが、おそらく DI に近いものです。
違いは、彼らが何を達成しようとしているのかです。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());
依存性注入を正当化する理由はいくつかありますが、主な理由はテスト用です。なんらかの永続化エンジン (データベースなど) がある場合があるかもしれません。ただし、テストを繰り返し実行している場合、実際のデータベースを使用するのは面倒な場合があります。したがって、テスト ケースでは、オーバーヘッドが発生しないように、ダミー データベースを挿入します。
この例を使用すると、違いがわかります。私たちは常にデータ ストレージ戦略を使用することを計画しており、それを渡すもの (実際の DB インスタンス) です。ただし、開発とテストでは、異なる依存関係を使用したいので、異なる具象を注入します。
DIを戦略パターンとして使用できるため、各顧客に必要なアルゴリズムを交換できますが、DIは、アプリケーションの一部ではない部分を分離する方法であるため、それを超えることができます。戦略パターン。
DIは、戦略パターンの実際の目的であるIMOを薄め始めるため、名前が変更された戦略パターンであると言うのは危険です。
おい、依存性注入はより一般的なパターンであり、具象ではなく抽象化への依存性に関するものであり、すべてのパターンの一部ですが、戦略パターンはより具体的な問題の解決策です
これはウィキペディアからの定義です:
ディ:
オブジェクト指向コンピューター プログラミングにおける依存性注入 (DI) は、依存関係の解決から動作を分離するというコア原則を持つ設計パターンです。つまり、依存度の高いソフトウェア コンポーネントを分離するための手法です。
戦略パターン:
コンピューター プログラミングでは、戦略パターン (ポリシー パターンとも呼ばれます) は特定のソフトウェア設計パターンであり、実行時にアルゴリズムを選択できます。
戦略パターンは、アルゴリズムのファミリーを定義し、それぞれをオブジェクトとしてカプセル化し、それらを交換可能にする手段を提供することを目的としています。戦略パターンにより、アルゴリズムを使用するクライアントとは独立してアルゴリズムを変えることができます。
戦略は、物事の計算方法を変更するために使用される高レベルのものです。依存性注入を使用すると、計算方法だけでなく、そこにあるものも変更できます。
私にとっては、単体テストを使用すると明らかになります。本番コードの実行では、すべてのデータを非表示にします(つまり、プライベートまたは保護します)。一方、単体テストでは、ほとんどのデータが公開されているため、Assertsで確認できます。
戦略の例:
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つしかない場合でも、具体的な戦略インスタンスを管理(初期化など)する方法の知識を戦略オブジェクト内に隠すことができるため、便利です。
実際、依存性注入も Bridge パターンに非常によく似ています。私にとって (そして定義によると)、Bridge パターンはさまざまなバージョンの実装に対応するためのものであり、Strategy パターンはまったく異なるロジックのためのものです。しかし、サンプル コードは DI を使用しているように見えます。では、DI は単なる技術または実装にすぎないのでしょうか。
戦略は、依存性注入のスキルを使用するためのアリーナです。依存性注入を実装する実際の方法は次のとおりです。
- イベント
- Unity/構造マップの構成ファイル (またはプログラムによる) など。
- 拡張方法
- 抽象工場パターン
- 制御パターンの反転 (戦略と抽象ファクトリの両方で使用)
ただし、戦略が際立っていることが 1 つあります。ご存じのように、Unity ではアプリケーションの起動時にすべての依存関係が設定されており、それ以上変更することはできません。ただし、戦略はランタイム依存関係の変更をサポートしています。しかし、戦略の責任ではなく、依存関係を管理/注入する必要があります。
実際、戦略は依存性注入については話していません。必要に応じて、Strategy パターン内の Abstract Factory を介して実行できます。Strategy は、インターフェースを備えたクラスのファミリーを作成し、それを「再生」することについてのみ話します。プレイ中にクラスが異なる層にあることがわかった場合は、自分で注入する必要がありますが、戦略の仕事ではありません.