Click here to Skip to main content
Click here to Skip to main content

The Inversion of Control Pattern

, 17 Apr 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
An understanding of "The Inversion of Control" Pattern

Introduction

A design pattern is a common solution for a common problem that has already been identified and tested. In other words, it’s a guideline that must be adjusted depending on the context, not used in a single, non-changing syntax.

The Inversion of Control Pattern

The term Inversion of Control (IoC) is a computer programming technique wherein the flow of the control of an application is inverted. Rather than a caller deciding how to use an object, in this technique, the object called decides when and how to answer the caller, so the caller is not in charge of controlling the main flow of the application.

This approach makes your code flexible enough to be decoupled. It can be unaware of what is going on in the call stack because the called object doesn't need to make any assumptions about what the caller is doing.

The Dependency Injection pattern is simply a concrete implementation of the IoC. Unfortunately, as Martin Fowler specifies in his book, there is a lot of confusion about these terms, because the common IoC containers available for languages such as Java or .NET are typically identified as IoC containers, but the techniques implemented in your code when you use these frameworks is the Dependency Injection pattern, which is just one of the available concrete implementations for IoC. For example, if you plan to work with a modularized WPF/Silverlight application using a well-known framework such as Prism, you might implement IoC using the Service Locator pattern and not Dependency Injection because you need a global IoC container available for all the modules. Imagine that you have a simple LogWriter concept that is used to write a log message either to a specific database table or to a specified file. You might depict this as shown in Figure 1.

Using the Code

The UML diagram in Figure 1 is pretty clear; there’s an abstract BaseLogger class that exposes a WriteLog message, and two concrete classes that inherit from BaseLogger. These expose the method in two ways: one writes a log message to a database, the other to the file system. The following code shows the wrong way to use one of these concrete loggers— without applying an IoC implementation:

static void Main(string[] args)
{
	/* 
	*
	*  Wrong way
	*/
	var firstLogger = new FileLogger();
	firstLogger.WriteLog("Some Text.");
	var secondLogger = new DatabaseLogger();
	secondLogger.WriteLog("Some other Text.");
	Console.ReadKey();
}

The biggest problem with this approach—not applying an IoC implementation—is that if you want to specify a different log at runtime, you’ll need to rewrite some code. That’s a huge architectural constraint. For example, suppose that you want to get rid of the FileLogger object. That’s not easy. You can’t simply eliminate it, because the application wouldn’t execute any more, or at least, you would need to modify and recompile it for it to continue working.

To solve the problem, the first step is to decouple the existing hierarchy by using an interface instead of the base abstract class, as illustrated in Figure 2. This way, you simply define a contract between a concrete log and its interface. Subsequently, to write a log message to a different location, you just need to render the interface in a specific way.

The code that follows is a refactored version that uses an IoC approach to declare the type of logger to be used at runtime. This approach is still procedural, because it decides which logger to use, but at least it decouples the code, so this is a somewhat more flexible version of the custom writer.

/// <span class="code-SummaryComment"><summary>
</span>/// Custom writer that can uses any log
/// <span class="code-SummaryComment"></summary>
</span>public sealed class Writer
{
	/// <span class="code-SummaryComment"><summary>
</span>	/// Accessor to the injected logger
	/// <span class="code-SummaryComment"></summary>
</span>	private ILogger logger;

	/// <span class="code-SummaryComment"><summary>
</span>	/// Initializes a new instance of the <span class="code-SummaryComment"><see cref="Writer"/> class.
</span>	/// <span class="code-SummaryComment"></summary>
</span>	/// <span class="code-SummaryComment"><param name="logger">The logger.</param>
</span>	public Writer(ILogger logger)
	{
		this.logger = logger;
	}

	/// <span class="code-SummaryComment"><summary>
</span>	/// Writes the specified message.
	/// <span class="code-SummaryComment"></summary>
</span>	/// <span class="code-SummaryComment"><param name="message">The message.</param>
</span>	public void Write(string message)
	{
		this.logger.WriteLog(message);
	}
}

At this point, you need something between the application and the logger that can resolve which logger to use at runtime. The following example uses procedural code to do that without using the Dependency Injection or the Service Locator patterns:

static void Main(string[] args)
{
	// IoC without an IoC container
	var firstLogger = new FileLogger();
	//Injectin of a specific logger
	var writer = new Writer(firstLogger);
	writer.Write("Log for the File system.");
	Console.ReadKey();
}

Points of Interest

An alternative solution would be to implement the Dependency Injection or the Service Locator.

History

  • 16th April, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

AbhishekGoenka
Architect
India India
I spent some time working as a programmer and computer developer for several IT companies. I gained a lot of knowledge and experience in the process, and met some very supportive people in the industry. In May 2000' I joined LBS College for Higher studies.
 
I enjoyed my studies as much as academic studies can be enjoyed. I feel that I depend my understanding of computers because of them. The LBS College gives his students a high level of studying, but my main problem with it is that its tests are sometimes completely out of sync with the material that is learned, too long and/or too hard, and so students receive low grades and are frustrated. This is especially demotivating considering the fact that studying there is a lot of work.
Follow on   Google+

Comments and Discussions

 
GeneralMy vote of 5 PinmemberI A Khan19-Apr-11 19:44 
GeneralMy vote of 5 PinmemberOshtri Deka19-Apr-11 9:33 
GeneralMy vote of 4 Pinmemberxondokan19-Apr-11 4:46 
GeneralDependency Injection? PinmemberRichardJMoss18-Apr-11 22:32 
Nice article, although I think for those of use who actually want to use the functionality, a brief explanation of actually *how* to do dependency injection would have been most helpful. I felt the article ended too abruptly in this regard.
GeneralRe: Dependency Injection? PinmemberAbhishekGoenka19-Apr-11 2:14 
GeneralRe: Dependency Injection? PinmemberRichardJMoss19-Apr-11 3:58 
GeneralRe: Dependency Injection? PinmemberAbhishekGoenka19-Apr-11 4:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 17 Apr 2011
Article Copyright 2011 by AbhishekGoenka
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid