控制反转是一种通用的软件架构设计原则,有助于创建可重用、模块化的软件框架,易于维护。
它是一种设计原则,其中控制流从通用编写的库或可重用代码“接收”。
为了更好地理解它,让我们看看我们在编程早期如何编写代码。在过程式/传统语言中,业务逻辑通常控制应用程序的流程,并“调用”通用或可重用的代码/函数。例如,在简单的控制台应用程序中,我的控制流由程序指令控制,可能包括对一些通用可重用函数的调用。
print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);
//More print and scan statements
<Do Something Interesting>
//Call a Library function to find the age (common code)
print Age
相比之下,使用控制反转(IoC)时,框架是可重用的代码,用于“调用”业务逻辑。
例如,在基于Windows的系统中,已经有一个框架可用于创建诸如按钮、菜单、窗口和对话框等UI元素。当我编写应用程序的业务逻辑时,框架的事件将调用我的业务逻辑代码(在触发事件时),而不是相反。
虽然框架的代码不知道我的业务逻辑,但它仍然知道如何调用我的代码。这是通过事件/委托、回调等实现的。在这里,控制流程被“倒置”。
因此,控制流不再依赖于静态绑定的对象,而是依赖于整个对象图和不同对象之间的关系。
依赖注入是一种实现对象依赖项的IoC原则的设计模式。
简单地说,当您尝试编写代码时,您将创建和使用不同的类。一个类(Class A)可能会使用其他类(Class B和/或D)。因此,类B和D是类A的依赖项。
一个简单的类比可以是一个汽车类。汽车可能依赖于其他类,如发动机、轮胎等。
依赖注入建议,应该将类注入其依赖关系的具体实例,而不是依赖类(例如汽车类)创建其依赖项(例如引擎类和轮胎类)。
让我们通过一个更实际的例子来理解。假设您正在编写自己的文本编辑器。除其他功能外,您可以拥有一个拼写检查器,为用户提供检查其文本中拼写错误的工具。这样一个简单的代码实现可以是:
Class TextEditor
{
EnglishSpellChecker objSpellCheck;
String text;
public void TextEditor()
{
objSpellCheck = new EnglishSpellChecker();
}
public ArrayList <typos> CheckSpellings()
{
}
}
乍一看,一切都看起来很顺利。用户将写入一些文本。开发人员将捕获该文本并调用CheckSpellings函数,然后找到一系列拼写错误,并将其显示给用户。
一切似乎都很好,直到有一天有一个用户开始在编辑器中使用法语。
为了支持更多的语言,我们需要有更多的拼写检查器。可能是法语、德语、西班牙语等。
在这里,我们创建了一个紧密耦合的代码,“English”SpellChecker与我们的TextEditor类紧密耦合,这意味着我们的TextEditor类依赖于EnglishSpellChecker或者换句话说,EnglishSpellChecker是TextEditor的依赖项。我们需要消除这种依赖关系。此外,我们的文本编辑器需要一种方式,在运行时根据开发人员的决定来保留任何拼写检查程序的具体引用。
因此,正如我们在DI的介绍中所看到的那样,它建议应向类注入其依赖项。因此,将所有依赖项注入到所调用的类/代码中应由调用代码负责。因此,我们可以重组我们的代码。
interface ISpellChecker
{
Arraylist<typos> CheckSpelling(string Text);
}
Class EnglishSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
}
}
Class FrenchSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
}
}
在我们的例子中,TextEditor类应该接收ISpellChecker类型的具体实例。
现在,这个依赖可以通过构造函数、公共属性或方法注入。
让我们尝试使用构造函数依赖注入来更改我们的类。修改后的TextEditor类将如下所示:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
这样,当调用代码创建文本编辑器时,可以将适当的SpellChecker类型注入到TextEditor实例中。
您可以在此处阅读完整文章。