답변:
DI와 Strategy는 같은 방식으로 작동하지만 Strategy는 더 세분화되고 수명이 짧은 종속성에 사용됩니다.
개체가 "고정 된"전략으로 구성되면 (예 : 개체가 구성 될 때) 전략과 DI의 구분이 흐려집니다. 그러나 DI 시나리오에서는 객체의 종속성이 수명 동안 변경되는 것이 더 드물지만 전략에서는 드물지 않습니다.
또한 전략을 메서드에 인수로 전달할 수 있지만 메서드 인수 주입의 관련 개념은 널리 퍼져 있지 않으며 대부분 자동화 된 테스트의 컨텍스트에서만 사용됩니다.
전략은 의도에 초점을 맞추고 동일한 행동 계약을 따르는 다른 구현으로 인터페이스를 만들도록 권장합니다. DI는 단지 일부 동작을 구현하고 제공하는 것에 관한 것입니다.
DI를 사용하면 구현의 일부를 교체 할 수있는 것 이외의 다른 이유로 프로그램을 분해 할 수 있습니다. 하나의 구현만으로 DI에서 사용되는 인터페이스는 매우 일반적입니다. 구체적인 구현이 하나 뿐인 "전략"은 실제 문제는 아니지만 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
차이점은 그들이 달성하려는 것입니다. 전략 패턴은 구현을 교체하려는 상황에서 사용됩니다. 예를 들어 다양한 방식으로 데이터를 포맷 할 수 있습니다. 전략 패턴을 사용하여 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가 단지 이름이 바뀐 전략 패턴이라고 말하는 것은 위험 할 것입니다.
야, 의존성 주입은 더 일반적인 패턴이고, 그것은 구체화가 아닌 추상화에 대한 의존성에 관한 것이며 모든 패턴의 일부이지만 전략 패턴은 더 구체적인 문제에 대한 해결책입니다.
이것은 wikipedia의 정의입니다.
DI :
객체 지향 컴퓨터 프로그래밍의 DI (Dependency Injection)는 동작을 종속성 해결과 분리하는 핵심 원칙이있는 디자인 패턴입니다. 즉, 고도로 종속 된 소프트웨어 구성 요소를 분리하는 기술입니다.
전략 패턴 :
컴퓨터 프로그래밍에서 전략 패턴 (정책 패턴이라고도 함)은 런타임에 알고리즘을 선택할 수있는 특정 소프트웨어 디자인 패턴입니다.
전략 패턴은 알고리즘 패밀리를 정의하고 각 알고리즘을 객체로 캡슐화하고 상호 교환 가능하게 만드는 수단을 제공하기위한 것입니다. 전략 패턴을 사용하면 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있습니다.
전략은 사물이 계산되는 방식을 변경하는 데 사용되는 상위 수준의 사물입니다. 의존성 주입을 사용하면 계산 방법뿐만 아니라 거기에있는 내용도 변경할 수 있습니다.
저에게는 단위 테스트를 사용할 때 명확 해집니다. 프로덕션 코드 실행을 위해 모든 데이터가 숨겨져 있습니다 (예 : 비공개 또는 보호됨). 반면 단위 테스트에서는 대부분의 데이터가 공개되어 있으므로 Assert로 볼 수 있습니다.
전략의 예 :
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 개의 검사를 확인합니다. 그들은 테스트중인 클래스에 주입 된 테스트 이중의 공개 데이터를 사용했습니다. 데이터 숨김 원칙 때문에 프로덕션 코드로는이 작업을 수행 할 수 없습니다. 프로덕션 코드에 특수 목적 테스트 코드를 삽입하고 싶지 않았습니다. 공개 데이터는 다른 클래스에 있어야했습니다.
테스트 더블이 주입되었습니다. 이는 기능뿐만 아니라 데이터에 영향을 미치기 때문에 단순한 전략과 다릅니다 .
의존성 주입은 제가 간략하게 설명 할 전략 패턴의 개선입니다. 런타임에 여러 대체 모듈 중에서 선택해야하는 경우가 많습니다. 이러한 모듈은 모두 공통 인터페이스를 구현하므로 서로 바꿔서 사용할 수 있습니다. 전략 패턴의 목적은 의사 결정 과정을 전략 객체라고 부르는 별도의 객체로 캡슐화하여 사용할 모듈 (즉, "구체적인 전략"또는 종속성)을 결정하는 부담을 없애는 것입니다.
종속성 주입은 사용할 구체적인 전략을 결정하는 것뿐만 아니라 구체적인 전략의 인스턴스를 생성하고이를 호출 모듈에 다시 "주입"하여 전략 패턴을 구체화합니다. 구체적인 전략 인스턴스를 관리 (초기화 등)하는 방법에 대한 지식이 전략 개체 내에 숨겨 질 수 있으므로 단일 종속성 만있는 경우에도 유용합니다.
전략은 의존성 주입 기술을 사용하는 분야입니다. 종속성 주입을 구현하는 실제 방법은 다음과 같습니다.
하지만 전략이 차별화되는 한 가지가 있습니다. 애플리케이션이 시작될 때 Unity에서 알다시피 모든 종속성이 설정되어 더 이상 변경할 수 없습니다. 그러나 전략은 런타임 종속성 변경을 지원합니다. 하지만 우리는 전략의 책임이 아니라 의존성을 관리 / 주입해야합니다!
실제로 전략은 의존성 주입에 대해 이야기하지 않습니다. 필요한 경우 전략 패턴 내에서 Abstract Factory를 통해 수행 할 수 있습니다. 전략은 인터페이스가있는 클래스 패밀리를 만들고 함께 '놀이'하는 것에 대해서만 이야기합니다. 플레이하는 동안 클래스가 다른 계층에있는 것을 발견하면 직접 주입해야하지만 전략의 작업은 아닙니다.
SOLID 원칙을 고려한다면 Open Closed Principle에 전략 패턴을 사용하고 Dependency Inversion 원리에 Dependency Injection을 사용합니다.