Inversion of control
In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-written portions of a computer program receive the flow of control from a generic framework. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code.
Inversion of control is used to increase modularity of the program and make it extensible,[1] and has applications in object-oriented programming and other programming paradigms. The term was used by Michael Mattsson in a thesis,[2] taken from there[3] by Stefano Mazzocchi and popularized by him in 1999 in a defunct Apache Software Foundation project, Avalon, then further popularized in 2004 by Robert C. Martin and Martin Fowler.
The term is related to, but different from, the dependency inversion principle, which concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions. The general concept is also related to event-driven programming in that it is often implemented using IoC so that the custom code is commonly only concerned with the handling of events, whereas the event loop and dispatch of events/messages is handled by the framework or the runtime environment.
Contents
Overview[edit]
As an example, with traditional programming, the main function of an application might make function calls into a menu library to display a list of available commands and query the user to select one.[4] The library thus would return the chosen option as the value of the function call, and the main function uses this value to execute the associated command. This style was common in text based interfaces. For example, an email client may show a screen with commands to load new mail, answer the current mail, start a new mail, etc., and the program execution would block until the user presses a key to select a command.
With inversion of control, on the other hand, the program would be written using a software framework that knows common behavioral and graphical elements, such as windowing systems, menus, controlling the mouse, and so on. The custom code "fills in the blanks" for the framework, such as supplying a table of menu items and registering a code subroutine for each item, but it is the framework that monitors the user's actions and invokes the subroutine when a menu item is selected. In the mail client example, the framework could follow both the keyboard and mouse inputs and call the command invoked by the user by either means, and at the same time monitor the network interface to find out if new messages arrive and refresh the screen when some network activity is detected. The same framework could be used as the skeleton for a spreadsheet program or a text editor. Conversely, the framework knows nothing about Web browsers, spreadsheets or text editors; implementing their functionality takes custom code.
Inversion of control carries the strong connotation that the reusable code and the problem-specific code are developed independently even though they operate together in an application. Callbacks, schedulers, event loops, dependency injection, and the template method are examples of design patterns that follow the inversion of control principle, although the term is most commonly used in the context of object-oriented programming.
Inversion of control serves the following design purposes:
- To decouple the execution of a task from implementation.
- To focus a module on the task it is designed for.
- To free modules from assumptions about how other systems do what they do and instead rely on contracts.
- To prevent side effects when replacing a module.
Inversion of control is sometimes facetiously referred to as the "Hollywood Principle: Don't call us, we'll call you".
Background[edit]
Inversion of control is not a new term in computer science. Martin Fowler traces the etymology of the phrase back to 1988,[5] but it is closely related to the concept of program inversion described by Michael Jackson in his Jackson Structured Programming methodology in the 1970s.[6] A bottom-up parser can be seen as an inversion of a top-down parser: in the one case, the control lies with the parser, while in the other case, it lies with the receiving application.
Dependency injection is a specific type of IoC.[4] A service locator such as the Java Naming and Directory Interface (JNDI) is similar. In an article by Loek Bergman,[7] it is presented as an architectural principle.
In an article by Robert C. Martin,[8] the dependency inversion principle and abstraction by layering come together. His reason to use the term "inversion" is in comparison with traditional software development methods. He describes the uncoupling of services by the abstraction of layers when he is talking about dependency inversion. The principle is used to find out where system borders are in the design of the abstraction layers.
Description[edit]
In traditional programming, the flow of the business logic is determined by objects that are statically bound to one another. With inversion of control, the flow depends on the object graph that is built up during program execution. Such a dynamic flow is made possible by object interactions that are defined through abstractions. This run-time binding is achieved by mechanisms such as dependency injection or a service locator. In IoC, the code could also be linked statically during compilation, but finding the code to execute by reading its description from external configuration instead of with a direct reference in the code itself.
In dependency injection, a dependent object or module is coupled to the object it needs at run time. Which particular object will satisfy the dependency during program execution typically cannot be known at compile time using static analysis. While described in terms of object interaction here, the principle can apply to other programming methodologies besides object-oriented programming.
In order for the running program to bind objects to one another, the objects must possess compatible interfaces. For example, class A
may delegate behavior to interface I
which is implemented by class B
; the program instantiates A
and B
, and then injects B
into A
.
Implementation techniques[edit]
In object-oriented programming, there are several basic techniques to implement inversion of control. These are:
- Using a service locator pattern
- Using dependency injection, for example
- Constructor injection
- Parameter injection
- Setter injection
- Interface injection
- Using a contextualized lookup
- Using the template method design pattern
- Using the strategy design pattern
In an original article by Martin Fowler,[9] the first three different techniques are discussed. In a description about inversion of control types,[10] the last one is mentioned. Often the contextualized lookup will be accomplished using a service locator
Examples[edit]
Most frameworks such as .NET or Enterprise Java display this pattern:
public class ServerFacade {
public <K, V> V respondToRequest(K request) {
if (businessLayer.validateRequest(request)) {
Data data = DAO.getData(request);
return Aspect.convertData(data);
}
return null;
}
}
This basic outline in Java gives an example of code following the IoC methodology. It is important, however, that in the ServerFacade
a lot of assumptions are made about the data returned by the data access object (DAO).
Although all these assumptions might be valid at some time, they couple the implementation of the ServerFacade
to the DAO implementation. Designing the application in the manner of inversion of control would hand over the control completely to the DAO object. The code would then become
public class ServerFacade {
public <K, V> V respondToRequest(K request, DAO dao) {
return dao.getData(request);
}
}
The example shows that the way the method respondToRequest
is constructed determines if IoC is used. It is the way that parameters are used that define IoC. This resembles the message-passing style that some object-oriented programming languages use.
控制反转
维基百科,自由的百科全书
跳转到导航跳转到搜索
在软件工程中,控制反转 (IoC) 是一种编程原则。与传统控制流相比,IoC 反转了控制流。在 IoC 中,计算机程序的自定义编写部分从通用框架接收控制流。与传统的过程编程相比,具有这种设计的软件架构颠倒了控制:在传统编程中,表达程序目的的自定义代码调用可重用的库来处理通用任务,但在控制反转时,它是框架调用自定义或特定于任务的代码。
控制反转用于增加程序的模块化并使其可扩展,[1] 并在面向对象编程和其他编程范式中得到应用。该术语由 Michael Mattsson 在一篇论文中使用,[2] 取自 Stefano Mazzocchi 的论文 [3],并于 1999 年在一个已不复存在的 Apache 软件基金会项目 Avalon 中推广,然后在 2004 年由 Robert C. Martin 和马丁福勒。
该术语与依赖倒置原则有关,但与依赖倒置原则不同,后者涉及通过共享抽象解耦高层和低层之间的依赖关系。一般概念也与事件驱动编程有关,因为它通常使用 IoC 实现,因此自定义代码通常只关注事件的处理,而事件循环和事件/消息的调度由框架或运行时环境。
内容
1 概述
2 背景
3 说明
4 实现技术
5个例子
6 另见
7 参考文献
8 外部链接
概述
例如,在传统编程中,应用程序的主要功能可能会将函数调用到菜单库中,以显示可用命令列表并询问用户选择一个。[4]因此,库将返回所选选项作为函数调用的值,并且主函数使用该值来执行关联的命令。这种风格在基于文本的界面中很常见。例如,电子邮件客户端可能会显示一个屏幕,其中包含加载新邮件、回复当前邮件、开始新邮件等命令,并且程序执行将一直阻塞,直到用户按下某个键来选择命令。
另一方面,通过控制反转,程序将使用了解常见行为和图形元素(例如窗口系统、菜单、控制鼠标等)的软件框架编写。框架的自定义代码“填空”,例如提供菜单项表并为每个项目注册代码子例程,但它是框架监视用户的操作并在选择菜单项时调用子例程.在邮件客户端示例中,该框架可以同时跟踪键盘和鼠标输入并通过任何一种方式调用用户调用的命令,同时监视网络接口以找出新消息是否到达并在某些时候刷新屏幕。检测到网络活动。相同的框架可以用作电子表格程序或文本编辑器的框架。相反,该框架对 Web 浏览器、电子表格或文本编辑器一无所知。实现它们的功能需要自定义代码。
控制反转具有很强的含义,即可重用代码和特定于问题的代码是独立开发的,即使它们在应用程序中一起运行。回调、调度程序、事件循环、依赖注入和模板方法是遵循控制反转原则的设计模式的示例,尽管该术语最常用于面向对象编程的上下文中。
控制反转用于以下设计目的:
将任务的执行与实现分离。
将模块集中在其设计的任务上。
将模块从关于其他系统如何做他们所做的假设中解放出来,而是依赖于契约。
防止更换模块时产生副作用。
控制反转有时被戏称为“好莱坞原则:不要打电话给我们,我们会打电话给你”。
背景
控制反转并不是计算机科学中的新术语。 Martin Fowler 将这个短语的词源追溯到 1988 年,[5] 但它与迈克尔杰克逊在 1970 年代在他的杰克逊结构化编程方法中描述的程序反转概念密切相关。 [6]自底向上解析器可以看作是自顶向下解析器的反转:在一种情况下,控制权属于解析器,而在另一种情况下,它属于接收应用程序。
依赖注入是一种特定类型的 IoC。[4]服务定位器(例如 Java 命名和目录接口 (JNDI))与此类似。在 Loek Bergman 的一篇文章中,[7] 它是作为一种架构原则提出的。
在
Robert C. Martin 的一篇文章[8] 将依赖倒置原理和分层抽象结合在一起。他使用“反转”一词的原因是与传统的软件开发方法进行比较。当他谈论依赖倒置时,他通过层的抽象描述了服务的解耦。该原理用于找出抽象层设计中系统边界的位置。
描述
在传统编程中,业务逻辑的流向由相互静态绑定的对象决定。通过控制反转,流程取决于在程序执行期间建立的对象图。通过抽象定义的对象交互使这种动态流成为可能。这种运行时绑定是通过依赖注入或服务定位器等机制实现的。在 IoC 中,代码也可以在编译期间静态链接,但通过从外部配置读取其描述而不是直接引用代码本身来找到要执行的代码。
在依赖注入中,依赖对象或模块在运行时与它需要的对象耦合。在程序执行期间,哪个特定对象将满足依赖性通常无法在编译时使用静态分析知道。虽然这里是根据对象交互来描述的,但该原理可以应用于除面向对象编程之外的其他编程方法。
为了让正在运行的程序将对象相互绑定,对象必须具有兼容的接口。例如,类 A 可以将行为委托给由类 B 实现的接口 I;程序实例化 A 和 B,然后将 B 注入 A。
实现技术
在面向对象编程中,有几种基本技术可以实现控制反转。这些是:
使用服务定位器模式
使用依赖注入,例如
构造函数注入
参数注入
二传手注入
接口注入
使用上下文查找
使用模板方法设计模式
使用策略设计模式
在 Martin Fowler 的一篇原创文章中,[9] 讨论了前三种不同的技术。在关于控制类型反转的描述中,[10] 提到了最后一个。通常上下文查找将使用服务定位器完成
例子
大多数框架(例如 .NET 或 Enterprise Java)都显示这种模式:
公共类 ServerFacade {
public <K, V> V respondToRequest(K 请求) {
如果(businessLayer.validateRequest(请求)){
数据数据 = DAO.getData(request);
返回 Aspect.convertData(data);
}
返回空;
}
}
Java 中的这个基本大纲提供了一个遵循 IoC 方法的代码示例。然而,重要的是,在 ServerFacade 中,对数据访问对象 (DAO) 返回的数据做出了许多假设。
尽管所有这些假设在某些时候可能是有效的,但它们将 ServerFacade 的实现与 DAO 实现耦合。以控制反转的方式设计应用程序会将控制权完全交给 DAO 对象。然后代码会变成
公共类 ServerFacade {
public <K, V> V respondToRequest(K request, DAO dao) {
返回 dao.getData(request);
}
}
该示例显示方法 respondToRequest 的构造方式决定了是否使用 IoC。它是使用参数定义 IoC 的方式。这类似于某些面向对象的编程语言使用的消息传递风格。