当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当前回答
对我来说,IoC/DI正在向调用对象推出依赖项。超级简单。
非技术性的答案是,在你打开引擎之前,你可以更换汽车的引擎。如果一切正常(界面),你就很好了。
其他回答
我喜欢这样的解释:http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/
它开始很简单,还显示了代码示例。
消费者X需要被消费的类Y来完成某件事。这一切都很好,很自然,但X真的需要知道它使用Y吗?
如果X知道它使用的东西具有Y的行为、方法、财产等,而不知道谁真正实现了这些行为,这还不够吗?
通过提取X在Y中使用的行为的抽象定义(如下面的I所示),并让消费者X使用该行为的实例而不是Y,它可以继续做它所做的事情,而不必知道Y的细节。
在上图中,Y实现了I,X使用了I的一个实例。虽然很可能X仍然使用Y,但有趣的是X并不知道这一点。它只知道它使用了实现I的东西。
阅读文章了解更多信息和好处描述,如:
X不再依赖于Y更灵活,可以在运行时决定实现隔离代码单元,更容易测试
...
这是怎么一回事?反转(耦合)控制,更改方法签名的耦合方向。对于反向控制,方法签名的定义由方法实现(而不是方法的调用方)决定。此处完整解释
它解决了哪个问题?方法上的自顶向下耦合。这随后消除了重构的需要。
什么时候使用合适,什么时候不合适?对于定义良好的小型应用程序,如果没有太大的变化,可能会产生开销。然而,对于将要发展的定义较少的应用程序,它减少了方法签名的固有耦合。这使开发人员可以更自由地开发应用程序,避免了对代码进行昂贵的重构。基本上,允许应用程序在很少返工的情况下发展。
控制权倒置是项目责任转移的一个指标。
当依赖项被授予直接作用于调用者空间的能力时,每次都会发生控制反转。
最小的IoC是通过引用传递变量,让我们先看看非IoC代码:
function isVarHello($var) {
return ($var === "Hello");
}
// Responsibility is within the caller
$word = "Hello";
if (isVarHello($word)) {
$word = "World";
}
现在,让我们通过将结果的责任从调用者转移到依赖项来反转控制:
function changeHelloToWorld(&$var) {
// Responsibility has been shifted to the dependency
if ($var === "Hello") {
$var = "World";
}
}
$word = "Hello";
changeHelloToWorld($word);
下面是另一个使用OOP的示例:
<?php
class Human {
private $hp = 0.5;
function consume(Eatable $chunk) {
// $this->chew($chunk);
$chunk->unfoldEffectOn($this);
}
function incrementHealth() {
$this->hp++;
}
function isHealthy() {}
function getHungry() {}
// ...
}
interface Eatable {
public function unfoldEffectOn($body);
}
class Medicine implements Eatable {
function unfoldEffectOn($human) {
// The dependency is now in charge of the human.
$human->incrementHealth();
$this->depleted = true;
}
}
$human = new Human();
$medicine = new Medicine();
if (!$human->isHealthy()) {
$human->consume($medicine);
}
var_dump($medicine);
var_dump($human);
*)免责声明:现实世界中的人类使用消息队列。
真的不明白为什么会有很多错误的答案,甚至被接受的答案也不太准确,这让人很难理解。真相总是简单明了的。
正如@Schneider在@Mark Harrison的回答中所评论的,请阅读Martin Fowler关于IoC的帖子。
https://martinfowler.com/bliki/InversionOfControl.html
我最喜欢的是:
这种现象就是控制反转(也称为好莱坞原则——“不要打电话给我们,我们会打电话给你”)。
为什么?
IoC的Wiki,我可以引用一段话。
控制反转用于增加程序的模块性并使其可扩展。。。随后在2004年由Robert C.Martin和Martin Fowler进一步推广。
Robert C.Martin:《清洁代码:敏捷软件工艺手册》的作者。
马丁·福勒:《重构:改进现有代码的设计》一书的作者。
由于这个问题已经有很多答案,但没有一个显示反转控制项的分解,我认为有机会给出一个更简洁和有用的答案。
控制反转是一种实现依赖反转原理(DIP)的模式。DIP声明如下:1。高级模块不应依赖于低级模块。两者都应该依赖于抽象(例如接口)。2.摘要不应依赖于细节。细节(具体实现)应该依赖于抽象。
控制反转有三种类型:
界面反转提供程序不应定义接口。相反,使用者应该定义接口,提供者必须实现它。接口反转允许消除每次添加新提供者时修改使用者的必要性。
流量反演更改流量控制。例如,您有一个控制台应用程序,要求输入许多参数,在输入每个参数后,您必须按enter键。您可以在此处应用Flow Inversion,并实现桌面应用程序,用户可以选择输入参数的顺序,用户可以编辑参数,在最后一步,用户只需按Enter键一次。
创建反转它可以通过以下模式实现:工厂模式、服务定位器和依赖注入。创建反转有助于消除类型之间的依赖关系,将依赖关系对象创建过程移到使用这些依赖关系对象的类型之外。为什么依赖关系不好?这里有几个例子:在代码中直接创建一个新对象会使测试更加困难;不重新编译就不可能更改程序集中的引用(违反OCP原则);你不能轻易地用web UI替换桌面UI。