战略模式和dependency injection之间有什么区别?
策略模式和dependency injection都允许我们在运行时设置/注入对象。 战略模式和dependency injection之间有什么区别?
DI和Strategy的工作方式相同,但Strategy用于更细粒度和短暂的依赖关系。
当一个对象被configuration了一个“固定的”策略时,例如当对象被构造时,策略和DI之间的区别模糊。 但是在DIscheme中,对象的依赖关系在其生命周期中发生变化更为不寻常,而战略并不罕见。
另外,可以将策略作为parameter passing给方法,而方法参数注入的相关概念并不普遍,大多只用于自动化testing。
策略侧重于意图,并鼓励您创build一个遵循相同行为契约的不同实现的接口。 DI更多的是关于一些行为的实现和提供。
使用DI,您可以将程序分解为其他原因,而不仅仅是交换部分实现。 DI中使用的接口只有一个实现是非常普遍的。 只有一个具体实现的“策略”不是一个真正的问题,但可能更接近DI。
不同的是他们正在努力实现的。 策略模式用于您知道要换出实现的情况。 例如,您可能想要以不同的方式格式化数据 – 您可以使用策略模式来交换XML格式化程序或CSV格式化程序等。
dependency injection的不同之处在于用户不会尝试更改运行时行为。 按照上面的例子,我们可能会创build一个使用XML格式化程序的XML导出程序。 而不是像这样构build代码:
public class DataExporter() { XMLFormatter formatter = new XMLFormatter(); }
你可以在构造函数中注入formatter:
public class DataExporter { IFormatter formatter = null; public DataExporter(IDataFormatter dataFormatter) { this.formatter = dataFormatter; } } DataExporter exporter = new DataExporter(new XMLFormatter());
dependency injection有一些理由,但主要的是testing。 你可能会遇到某种types的持久化引擎(比如数据库)的情况。 但是,当您重复运行testing时,使用真实的数据库可能会很痛苦。 所以,对于你的testing用例,你会注入一个虚拟的数据库,所以你不会承担这个开销。
使用这个例子,你可以看到不同之处:我们总是计划使用数据存储策略,这是我们传入的(真正的数据库实例)。 但是,在开发和testing中,我们要使用不同的依赖关系,所以我们注入不同的结果。
您可以使用DI作为策略模式,这样您就可以交换每个客户所需的algorithm,但是DI可以超越,因为这是解耦应用程序各部分的一种方式,而这不属于战略模式。
如果说DI只是一种改名的战略模式,那么开始稀释战略模式的真正目的就是IMO。
老兄,dependency injection是一个更普遍的模式,它是依赖于抽象而不是结核,它是每个模式的一部分,但是策略模式是一个更具体问题的解决scheme
这是维基百科的定义:
DI:
面向对象计算机编程中的dependency injection(DI)是一种devise模式,其核心原则是将行为与依赖关系parsing分开。 换句话说:一种解耦高度依赖的软件组件的技术。
战略模式:
在计算机编程中,策略模式(也称为策略模式)是一种特定的软件devise模式,可以在运行时selectalgorithm。
策略模式旨在提供一种方法来定义一系列algorithm,将每个algorithm封装为一个对象,并使它们可以互换。 策略模式让algorithm独立于使用它们的客户端。
策略是用来改变事物计算方式的更高层次的东西。 通过dependency injection,不仅可以改变事物的计算方式,而且还可以改变那里的情况。
对我来说,使用unit testing变得很清楚。 对于生产代码执行,您隐藏所有数据(即私有或受保护); 而在unit testing中,大部分数据都是公开的,所以我可以用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 (...); } }
请注意,这些策略之间没有公共数据是不同的。 也没有任何不同的方法。 两种策略共享所有相同的function和签名。
现在进行dependency injection:
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个检查。 他们使用被注入到被testing的class级中的testing双数据中的公共数据。 由于数据隐藏原理,我不能用生产代码来做这件事。 我不想在生产代码中插入特殊用途的testing代码。 公共数据必须在不同的类别中。
testing双注射。 这不仅仅是一个策略,因为它影响到数据而不仅仅是function。
dependency injection是我将简要解释的一种策略模式的改进。 在运行时经常需要在几个可选模块之间进行select。 这些模块都实现了一个通用接口,以便它们可以互换使用。 策略模式的目的是通过把决策过程封装成一个单独的对象,我称之为策略对象来消除决定使用哪个模块(即哪个“具体策略”或依赖)的负担。
dependency injection改进了策略模式,不仅决定使用哪个具体策略,而且创build一个具体策略的实例,并将其“注入”callback用模块。 这是有用的,即使只有一个依赖作为如何pipe理(初始化等)具体策略实例的知识也可以隐藏在策略对象内。
实际上,dependency injection看起来也和Bridge模式非常相似。 对我来说(根据定义),Bridge模式是为了适应不同版本的实现,而Strategy模式则是为了完全不同的逻辑。 但示例代码看起来像使用DI。 所以也许DI只是一个技术或实现?
战略是一个使用你的dependency injection技能的舞台。 实现dependency injection的真正方法如下:
- 活动
- 统一/结构图(或编程)的configuration文件等
- 扩展方法
- 抽象的工厂模式
- 控制模式的反转(策略和抽象工厂都使用)
有一件事让战略立场分开。 正如你在Unity中所知道的那样,当应用程序启动时,所有的依赖关系都被设置好了,我们不能再进行更改。 但是策略支持运行时依赖性的改变。 但是我们必须pipe理/注入依赖,而不是策略的责任!
其实战略并不谈论dependency injection。 如果需要的话,可以通过战略模式中的抽象工厂完成。 战略只是谈论创build一个界面和“玩”的类家庭。 在玩游戏的时候,如果我们发现课程是在不同的层次,那么我们必须自己注入,而不是战略的工作。