Inversion of Control

Inversion of Control (IoC) is a design principle that refers to the concept of letting an external entity, usually a framework or a container, manage the flow of control in a software application. In IoC, instead of the application taking charge of the flow of control, it delegates the control to an external entity, which decides when to invoke which methods and when.

For example, in an old school menu, you might have:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database
Bash

thereby controlling the flow of user interaction.

In a GUI program or some such, instead we say:

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase
Bash

So now control is inverted… instead of the computer accepting user input in a fixed order, the user controls the order in which the data is entered, and when the data is saved in the database.

IoC & DI

Dependency Injection (DI) and Inversion of Control (IoC) are related concepts in software engineering, but they are not exactly the same.

DI refers to the process of injecting dependencies into a component or object, rather than having the component create or obtain its dependencies itself. This allows for greater flexibility, as the dependencies can be swapped out or mocked for testing purposes. DI is a technique used to implement IoC.

IoC, on the other hand, refers to the broader concept of letting an external entity manage the flow of control in an application. In IoC, the application delegates the control to an external entity, which decides when to invoke which methods and when. This allows for greater flexibility, scalability, and modularity in the system.

In short, DI is a technique for achieving IoC, while IoC is a broader concept that encompasses DI as well as other techniques for managing the flow of control in an application.

Framework vs Library from IoC Point of View

Inversion of Control is a key part of what makes a framework different to a library. A library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.

A framework embodies some abstract design, with more behavior built in. In order to use it you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework’s code then calls your code at these points.

How to achieve IoC

Inversion of Control (IoC) is a design pattern that can be achieved through various techniques, including Dependency Injection (DI), Service Locator, and Template Method.

Here are some ways to achieve IoC:

  1. Dependency Injection (DI): In DI, the dependencies required by an object are provided to it by an external source, rather than the object creating or obtaining the dependencies itself. This allows for greater flexibility and testability, as the dependencies can be easily swapped out or mocked for testing purposes. DI can be achieved using constructor injection, setter injection, or method injection.
  2. Service Locator: In the Service Locator pattern, an external service locator is used to locate and provide the required dependencies to an object. The object requests the dependencies from the service locator, which is responsible for locating and providing them. This allows for greater flexibility and modularity in the system.
  3. Template Method: In the Template Method pattern, an abstract class defines a skeleton of an algorithm, with some of the steps left to be implemented by concrete subclasses. The abstract class defines the flow of control, while the concrete subclasses provide the specific implementation details. This allows for greater flexibility and modularity in the system.
  4. Inversion of Control Containers: Inversion of Control Containers, such as Spring or .NET Core, provide a framework for managing dependencies and components in an application. The container is responsible for creating and managing the components and their dependencies, and for providing them to other components as required. This allows for greater flexibility and modularity in the system.

Refactoring Highly Coupled code to achieve Loose Coupling

  1. Identify the dependencies
  2. Use Dependency Injection
  3. Use interfaces: Use interfaces to abstract the implementation details of your components from their interfaces. This allows you to easily swap out components with different implementations that conform to the same interface.
  4. Use design patterns: Use design patterns, such as the Factory pattern, Singleton pattern, or Observer pattern, to decouple components from each other and to promote modularity and flexibility in your code.

Read More:

https://martinfowler.com/bliki/InversionOfControl.html

https://en.wikipedia.org/wiki/Inversion_of_control