策略模式和依赖注入都允许我们在运行时设置/注入对象。策略模式和依赖注入之间有什么区别?
答案 0 :(得分:94)
DI和策略以相同的方式工作,但策略用于更细粒度和短期的依赖关系。
当对象配置了“固定”策略时,例如构建对象时,策略和DI之间的区别模糊。但是在DI场景中,对象的依赖关系在其生命周期中会发生变化,这种情况更为罕见,而战略并不罕见。
此外,您可以将策略作为参数传递给方法,而方法参数注入的相关概念并不普遍,主要用于自动化测试的上下文中。
策略侧重于意图,并鼓励您创建具有遵循相同行为合同的不同实现的接口。 DI更多的是关于实现某些行为并提供它。
使用DI,您可以出于其他原因分解您的程序,而不仅仅是为了能够交换部分实现。 DI中使用的接口只有一个实现是很常见的。只有一个具体实施(永远)的“战略”不是一个真正的问题,但可能更接近DI。
答案 1 :(得分:35)
不同之处在于他们正在努力实现的目标。策略模式用于您知道要替换实现的情况。例如,您可能希望以不同的方式格式化数据 - 您可以使用策略模式来交换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());
依赖注入有一些理由,但主要用于测试。您可能遇到某种类型的持久性引擎(例如数据库)。但是,当您重复运行测试时,使用真实数据库可能会很麻烦。因此,对于您的测试用例,您将注入一个虚拟数据库,这样就不会产生这种开销。
使用这个例子,您可以看到不同之处:我们总是计划使用数据存储策略,它是我们传入的策略(真正的数据库实例)。但是,在开发和测试中,我们希望使用不同的依赖关系,因此我们注入了不同的具体结构。
答案 2 :(得分:27)
您可以使用DI作为策略模式,因此您可以交换每个客户所需的算法,但DI可以超越它,因为它只是解耦应用程序的各个部分,而不是成为战略模式的一部分。
说DI只是一种重新命名的策略模式会有风险,因为它开始淡化战略模式的真正含义,IMO。
答案 3 :(得分:12)
Dude,依赖注入是一种更普遍的模式,它是关于抽象的依赖而不是具体结构,它是每个模式的一部分,但战略模式是解决更具体问题的方法
这是维基百科的定义:
DI:
依赖注入(DI)in 面向对象的计算机编程 是一个核心的设计模式 分离行为的原则 依赖解决。换一种说法: 一种高度解耦的技术 依赖软件组件。
策略模式:
在计算机编程中,策略 模式(也称为政策 pattern)是一种特殊的软件 设计模式,算法可以 在运行时选择。
策略模式旨在 提供一种定义一个家庭的方法 算法,将每个算法封装为 对象,并使它们可以互换。 战略模式让我们 算法独立于 使用它们的客户。
答案 4 :(得分:6)
策略是用于改变事物计算方式的更高级别的事物。使用依赖注入,您不仅可以更改事物的计算方式,还可以更改其中的内容。
对我来说,使用单元测试时会很清楚。对于生产代码执行,您隐藏所有数据(即私有或受保护);然而,通过单元测试,大多数数据都是公开的,因此我可以使用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次检查。他们使用注入被测试类的测试双重中的公共数据。由于数据,我无法使用生产代码执行此操作 隐藏原则。我不想在生产代码中插入专用测试代码。公共数据必须属于不同的类别。
注射测试双。这不仅仅是一种策略,因为它影响了数据,而不仅仅是功能。
答案 5 :(得分:3)
依赖注入是战略模式的改进,我将简要解释。通常需要在运行时在几个备用模块之间进行选择。这些模块都实现了通用接口,因此它们可以互换使用。策略模式的目的是通过将决策过程封装到我将称为策略对象的单独对象中来消除决定使用哪个模块(即“具体策略”或依赖性)的负担。 / p>
依赖注入通过不仅决定使用哪种具体策略而且创建具体策略的实例并将其“注入”回调用模块来改进策略模式。即使只有一个依赖项,这也很有用,因为有关如何管理(初始化等)的知识,具体的策略实例也可以隐藏在策略对象中。
答案 6 :(得分:1)
实际上,依赖注入看起来与Bridge模式非常相似。对我而言(根据定义),Bridge模式适用于实现的不同版本,而策略模式适用于完全不同的逻辑。但示例代码看起来像是在使用DI。那么DI可能只是一种技术或实现吗?
答案 7 :(得分:0)
策略是使用依赖注入技能的舞台。 实现依赖注入的真正方法如下: -
但是有一件事让战略脱颖而出。正如您在Unity中所知,当应用程序启动时,所有依赖项都已设置,我们无法进一步更改它。但策略支持运行时依赖性更改。但我们必须管理/注入依赖,而不是战略的责任!
实际上策略并没有谈论依赖注入。如果需要,可以通过策略模式中的抽象工厂完成。策略只涉及创建一个具有界面和“玩”的类系列。在玩游戏的过程中,如果我们发现这些课程属于不同的等级,那么我们必须自己注入课程而不是战略工作。
答案 8 :(得分:0)
如果我们考虑SOLID原则 - 我们使用开放封闭原则的策略模式和依赖性反演原则的依赖注入