当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当前回答
控制权倒置是项目责任转移的一个指标。
当依赖项被授予直接作用于调用者空间的能力时,每次都会发生控制反转。
最小的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);
*)免责声明:现实世界中的人类使用消息队列。
其他回答
使用IoC,您不会对对象进行更新。您的IoC容器将做到这一点,并管理它们的生命周期。
它解决了必须手动将一种类型对象的每个实例化更改为另一种类型的问题。
如果您的功能将来可能会发生变化,或者根据中使用的环境或配置而有所不同,则使用此选项是合适的。
控制反转(IoC)模式是关于提供任何类型的回调,它“实现”和/或控制反应,而不是直接执行自己(换句话说,反转和/或将控制重定向到外部处理器/控制器)。依赖注入(DI)模式是IoC模式的一个更具体的版本,它完全是从代码中删除依赖项。
每个DI实现都可以被视为IoC,但不应该称之为IoC。因为实现依赖注入比回调更困难(不要使用通用术语“IoC”来降低产品的价值)。
例如DI,假设您的应用程序有一个文本编辑器组件,并且您希望提供拼写检查。你的标准代码应该是这样的:
public class TextEditor {
private SpellChecker checker;
public TextEditor() {
this.checker = new SpellChecker();
}
}
我们在这里所做的工作在TextEditor和SpellChecker之间创建了依赖关系。在IoC场景中,我们会这样做:
public class TextEditor {
private IocSpellChecker checker;
public TextEditor(IocSpellChecker checker) {
this.checker = checker;
}
}
在第一个代码示例中,我们正在实例化SpellChecker(this.checker=new SpellCheckr();),这意味着TextEditor类直接依赖于SpellChecker类。
在第二个代码示例中,我们通过在TextEditor的构造函数签名中使用SpellChecker依赖类(而不是在类中初始化依赖项)来创建抽象。这允许我们调用依赖项,然后将其传递给TextEditor类,如下所示:
SpellChecker sc = new SpellChecker(); // dependency
TextEditor textEditor = new TextEditor(sc);
现在,创建TextEditor类的客户端可以控制使用哪个SpellChecker实现,因为我们正在将依赖项注入TextEditor签名中。
注意,就像IoC是许多其他模式的基础一样,上面的示例只是依赖注入类型中的一种,例如:
构造函数注入。IocSpellChecker的实例将自动传递给构造函数,或手动传递给构造函数。沉淀剂注入。IocSpellChecker的实例将通过setter方法或公共属性传递。服务查找和/或服务定位器其中TextEditor将向已知的提供者请求IocSpellChecker类型的全局使用的实例(服务)(这可能不存储所述实例,而是一次又一次地询问提供者)。
控制权倒置是项目责任转移的一个指标。
当依赖项被授予直接作用于调用者空间的能力时,每次都会发生控制反转。
最小的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);
*)免责声明:现实世界中的人类使用消息队列。
所以上面的数字1。什么是控制反转?维护是它为我解决的首要问题。它保证我使用的是接口,这样两个类就不会彼此亲密。
使用温莎城堡这样的容器,它可以更好地解决维护问题。能够在不更改一行代码的情况下,将一个连接到数据库的组件替换为一个使用基于文件的持久性的组件,这是非常棒的(配置更改完成了)。
一旦你进入泛型,它会变得更好。想象一下,拥有一个接收记录并发布消息的消息发布者。它不在乎它发布了什么,但它需要一个映射器将记录中的内容转换为消息。
public class MessagePublisher<RECORD,MESSAGE>
{
public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
{
//setup
}
}
我写过一次,但现在如果我发布不同类型的消息,我可以向这组代码中注入许多类型。我还可以编写映射器,将相同类型的记录映射到不同的消息。将DI与Generics结合使用使我能够编写很少的代码来完成许多任务。
哦,是的,存在可测试性问题,但它们比IoC/DI的优势更为次要。
我绝对喜欢IoC/DI。
3.当你有一个中等规模的项目时,它会变得更加合适。我会说,当你开始感到疼痛时,它就变得合适了。
控制反转是关于分离关注点。
没有IoC:你有一台笔记本电脑,你不小心弄坏了屏幕。糟糕的是,你发现市场上没有同一型号的笔记本电脑屏幕。所以你被卡住了。
IoC:你有一台台式电脑,你不小心把屏幕弄坏了。你发现你可以从市场上买到几乎所有的桌面显示器,而且它与你的桌面很好地配合。
在这种情况下,您的桌面成功地实现了IoC。它接受各种类型的显示器,而笔记本电脑不接受,它需要一个特定的屏幕来固定。