Inversion of Control (IoC)

"In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow."
Wikipedia - Inversion of Control

The simple concept is that instead of a class specifying the related objects it needs, the control comes from outside the class. The goal is to make classes loosely coupled so that changes to one class don't force changes to another.

Martin Fowler describe two major types of IoC his article, Inversion of Control Containers and the Dependency Injection pattern. Dependency Injection (DI) implies injecting the dependency (required object) into the current object. A Service Locator implies that the current object makes a request to locate and retrieve te best object. In either case, the process of determining the correct object to retrieve is typically done through a configuration process.

The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.

Martin Fowler

There are religious debates between the patterns which I will certainly not address here other than to point out that Dependency Injection is not a reasonably viable option in Apex.

Dependency Injection implies injecting the dependency into the object. The most common case is constructor injection, in which the constructor has input parameters so that the dependencies can be passed in. There are also options for property injection in which the dependency is set in a property (usually public).

With a service locator, the class requests a dependency from some other class that is responsible for supplying the correct object.

True dependency injection is challenging in Salesforce. Apex does not fully support reflection like Java or C#, and it doesn't have a good mechanism to intercept constructor calls. While there are Apex libraries on github that use the term Dependency Injection, upon inspection you'll see that they really implement a Service Locator pattern.

To see useful code for a service locator pattern, please see this github repository. Please see the README.md file. It is useful to try to follow the code to fully understand the concept. Apart from classes to support testing, there is only one class and one small interface.

It is designed to meet the following requirements:

The developer asks for an object that implements a given interface.

Custom Metadata contains mapping of objects of which class will be return for requests to which interface.


To get an instance of a dependant class inside another class:
IMyTest test = (ServiceLocator.IMyTest) ServiceLocator.getInstance(ServiceLocator.IMyTest.class);

To resolve a dependency, the Service Locator checks these items in order (the first found item wins):

  1. The mapping is set explicitly in code.
  2. The Interface has been explicitly mapped in custom metadata.
  3. If it follows a convention that can return an object.
  4. Then finally throws a ServiceLocator.MapException if the Interface cannot be resolved to an object.

This process allows you to change which class is used dynamically by modifying specific custom metadata, even in production environments. It can also make writing unit test much easier.

 

 

© 2001 – 2023 Object Factory Inc
marker marker marker marker marker