Answers:
DI和Strategy以相同的方式工作,但是Strategy用于更细粒度和短暂的依赖关系。
当对象配置有“固定”策略时,例如,在构造对象时,策略和DI之间的区别就会模糊。但是在DI场景中,对象的依赖关系在它们的生命周期中会发生变化是很不寻常的,而这在Strategy中并不少见。
此外,您可以将策略作为方法的参数传递,而方法参数注入的相关概念并不广泛,并且仅在自动测试的上下文中使用。
策略专注于意图,并鼓励您创建一个遵循相同行为契约的具有不同实现的接口。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());
有一些关于依赖注入的理由,但是主要的理由是用于测试。您可能会遇到具有某种持久性引擎(例如数据库)的情况。但是,当您反复运行测试时,使用真实的数据库可能会很痛苦。因此,对于您的测试用例,您将注入一个虚拟数据库,以免产生开销。
使用本示例,您可以看到不同之处:我们始终计划使用数据存储策略,而这正是我们传入的策略(真实的数据库实例)。但是,在开发和测试中,我们想使用不同的依赖关系,因此我们注入了不同的构想。
杜德(Dude),依赖注入是一种更通用的模式,它是关于抽象而不是具体的依赖,它是每个模式的一部分,但是策略模式是解决更具体问题的方法
这是维基百科的定义:
DI:
面向对象的计算机编程中的依赖注入(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个检查。他们在注入测试类的测试双中使用了公共数据。由于数据隐藏原理,我无法使用生产代码执行此操作。我不想在生产代码中插入特殊目的的测试代码。公开数据必须位于不同的类中。
测试双被注入。这与策略不同,因为它不仅影响功能,而且影响数据。
策略是使用依赖注入技能的场所。实现依赖项注入的实际方法如下:
尽管有一件事使战略与众不同。如您所知,在Unity中,应用程序启动时,所有依赖项均已设置,我们无法对其进行进一步更改。但是策略支持运行时依赖项更改。但是我们必须管理/注入依赖性,而不是战略的责任!
实际上,策略并没有谈论依赖注入。如果需要,可以通过Strategy模式中的Abstract Factory来完成。策略只讨论创建具有接口的类家族并对其进行“播放”。在玩游戏时,如果我们发现班级在不同的层中,那么我们必须自己注入,而不是策略的工作。
如果我们考虑SOLID原则-我们将策略模式用于开放式封闭式原则,将依赖项注入用于依赖项倒置原则