Inversion of control is a common occurrence that you will encounter when using frameworks. Indeed, it is often viewed as a defining characteristic of the framework.
Let's look at a simple example. Imagine that I am writing a program that receives some information from the user using the command line. I could do it something like this:
')
In this situation, my code controls execution: it decides when to ask questions, when to read the answers, and when to process the results.
However, if I used the window system for something like this, I would write something that works with the window:
require 'tk' root = TkRoot.new() name_label = TkLabel.new() {text "What is Your Name?"} name_label.pack name = TkEntry.new(root).pack name.bind("FocusOut") {process_name(name)} quest_label = TkLabel.new() {text "What is Your Quest?"} quest_label.pack quest = TkEntry.new(root).pack quest.bind("FocusOut") {process_quest(quest)} Tk.mainloop()
Now there is a big difference in the control flow between these two programs - in particular, in time management, when the
process_name and
process_quest methods are called. In the command line example, I control when these methods are called, but not in the window application example. Instead, I pass control to the window system (
Tk.mainloop command). She then decides when to call my methods based on the connections I set up when creating the form. Management is inverted - they control me, but not I manage the framework. This phenomenon is called the inversion of control (also known as the
Hollywood Principle - “Do not call us, we will call you” -
Hollywood Principle - “Don't call us, you call you” ).
One important characteristic of the framework is that user-defined methods for adapting the framework to your needs will most often be called within the framework itself, rather than from the application code of the user. The framework often plays the role of the main program in the coordination and sequencing of an application. This inversion of control gives the framework the ability to serve as an extensible skeleton of the application. The methods provided by the user adapt the general algorithms defined by the framework for a specific application.
Ralph Johnson and Brian Foote.
Inversion of control is a key part of what distinguishes the framework and the library. A library is essentially a set of functions that you can invoke, these days they are organized into classes. Each call does some work and returns control back to the user.
The framework embodies some abstract design with embedded behavior. In order to use it, you must add your code in various places of the framework, either through inheritance or by connecting your own class. The framework code will subsequently invoke your code.
There are various ways to connect your code to call it further. In the previous ruby ​​example, we call the
bind method of the text field, which takes the name of the event and the
closure as arguments. Whenever a text field finds out about an event, it calls our code from the closure. The use of such closures is very convenient, but many languages ​​do not support them.
Another way to do this is to have the framework detect events and the user code subscribe to these events. .NET is a good example of a platform that allows people to announce their events to widgets using language tools. You can assign a method to an event using delegates.
The approaches discussed above (they are the same) are well suited in isolated cases, but sometimes you may need to combine a certain number of calls into a single extension block. In this case, the framework can define the interface that your code will need to implement for the corresponding calls.
EJB components are a good example of this style of inversion control. When designing the session bean, you can implement various methods that are invoked by the EJB container at various points / lifecycle states. For example, the
SessionBean interface has
ejbRemove ,
ejbPassivate (saved to secondary storage), and
ejbActivate (restored from passive state) methods. You cannot control the calling of these methods, just what they do. The container calls us, not we call it.
Translation note, example: public class EjbExample implements SessionBean { public void ejbActivate() throws EJBException, RemoteException {
These are complex cases of inversion control, but you will encounter this in much simpler situations.
The generic method is a good example: a superclass defines a control flow, subclasses inherit from it by overriding methods or implementing abstract methods. For example, in JUnit, the framework code calls the
setUp and
tearDown methods for you to create and clean up your test. A call occurs, your code reacts - this is again an inversion of control.
Translation note, example: public class SomeTest extends TestCase { protected void setUp() throws Exception { super.setUp();
Nowadays, due to the growing number of IoC containers, there is some confusion with the meaning of inversion of control. Some people confuse the general principle with the specific inversion of control styles (such as
dependency injection ) that these containers use. All of this is a bit confusing (and ironic), since IoC containers are usually considered to be competing with EJB, but EJB uses control inversion.
Etymology: As far as I can tell, the term inversion of control first appeared in the work of Johnson and Foote
Designing Reusable Classes , published in the journal Object-Oriented Programming in 1988. Work is one of those that are good at the age - it can be read even after fifteen years. They believe that they took this term from somewhere else, but cannot remember where they came from. Then the term was rubbed into the object-oriented community and reappeared in the book
Gang of Four . A more beautiful synonym for the “Hollywood Principle” seems to have originated
in the work of Richard Sweet at Mesa in 1983. In the list of development goals, he writes:
Do not call us, we will call you (the Law of Hollywood): the tool should organize Tahoe to warn him when the user wants to send some event to the tool, instead of accepting the model “request the user command and execute it .
" John Vlissides writes a
column on C ++ , which carries a good explanation of the concept called “The Hollywood Principle”. (Thanks to Brian Foote and Ralph Johnson for helping with etymology).
UPD: Added examples.