DIC
DIC stands for Dependency Injection Container. Dependency Injection (DI) is a mean to realize an inversion of control, a common design pattern. But, as promised, lets use simple terms.
A real world example
As an autonomous work- or craftsman, how to acquire contracts? Would you burgle arbitrary houses in order to remodel, say, the occupant’s kitchen the way you would like it to be? Rather not! Most likely you will be contacted by occupants who want their kitchen to be remodeled or you may ask them whether they want it to be remodeled. Anyway, they will tell you how they want it to be remodeled. The only thing you have to know is how the customer’s remodeling is done by means of tools to be used as well as craftsmanship.
The principle
The customer is always right! As a service provider you will have to kindly ask her or him what she or he would like to be done. Only the particular customer can really tell you what she or he wants to be done (first-hand or reference information). Your key question is
“May I kindly ask you to provide me with your means (in terms of knowledge) I depend on in order to do my work?”
Understanding the virtual concept
For an easier understanding − for now − let’s disregard the “injection”. Instead, let’s add the concept of a container holding dependencies. This container is the only instance (in terms of a reference) that knows about the insights of the dependencies. So it’s recommended to use the dependency container as a dictionary that white-lists valid dependencies. From outside the container, you cannot change dependencies, but only request the same.
A graphical representation
The following images depict the sequence of a dependency request. First an authenticated request to a registered dependency.
If the requester is not authenticated or the dependency isn’t registered, nothing is returned.
Applied to our real world example, that means that there is no omnipotent craftsman who actively alters unasked customers’ facilities but the customers let the craftsman do the work they want him to do. So control is not with the one who does (the craftsman or provider) but with the one who lets him do (the customer or consumer). At least in the real world example, this may not appear as being an inversion of control, but in software it is as there typically powerful functions work on “defenseless” data.
As the container is a single reference to dependencies, it realizes a dictionary or registry implemented as a singleton that cannot be instantiated.
So what about “injection”?
Having learned that it’s just a detail that makes up an injection. If a class (our craftsman) is implicitly provided with its dependencies (typically by means of its construct), these dependencies are referred to as being “injected” into the class.
Dependencies
After having mentioned this concept a couple of times, it may not be transparent what dependencies might be. Generally spoken dependencies are any kind of resources a requester might depend on.
Examples
- Language modules
- Configuration settings
- White-lists
- Data descriptions
- Database connections
- Session objects
Container variants
Dictionary
The container might be implemented as a read-only dictionary that white-lists valid dependencies.
Registry
An extended variant is to offer a registration interface in order to register dependencies to the central registry.
Advantages
Security
The inversion of control inhibits undesired results and thus behavior as a requester cannot alter the container’s internal logic. This is especially true when being used in typical web application environments where the container is a plain back-end implementation unreachable by the front-end (by different run-time environments and encapsulation).
Clarity, trust and maintainability
The container’s nature as a singleton makes it the only source of truth for dependencies, so a dependency is either always wrong or always right regardless of the requester. Maintaining or changing a dependency effects all its requesters at once.
Possible disadvantages
Design effort
When designing your own DI container, working out a maintainable and effective design may be expensive.
Implementation effort
Implementing your own DI container of course bears the respective effort.
No golden hammer
Using a DIC will mainly increase the maintainability of your code in terms of refraining you from bypassing your design, but it won’t necessarily refrain others (like an attacker) from doing so (e.g. by injecting SQL etc.).
Pseudo code example
Following a code snipset using a pseudo code to demonstrate an implementation approach.
Pseudo code
// Singleton (final) and static class Dependency Injection Container (DIC) final static class DIC { // The construct defines and initializes the properties construct() { // A public property that allows passing the application context public strCurrentApplication = NULL; // Private properties holding white-lists and configuration switches private arrRegisteredApplications = [ “app1”, “app2”, “app3”, … ]; private boolUseI18nModule = FALSE; private objDatabaseConnection = NULL; … } // Always check if set application is white-listed CheckIfRegisteredApplication() { if ( !in_array( self::strCurrentApplication, self::arrRegisteredApplications ) ) { throw Exception( “Unregistered application!” ); } // If application is white-listed, load its configuration LoadApplicationConfiguration( self::strCurrentApplication ) } // Load application configuration // Application configuration parameters may be defined statically or // loaded from external configurations (files or DB) LoadApplicationConfiguration() { // Set (or override default values of) // configuration switches and object references self::boolUseI18nModule = self::objDatabaseConnection = ... } // Finally, an interface returning a reference to the database connection ConnectDatabase() { if ( CheckIfRegisteredApplication ) { return self::objDatabaseConnection; } catch Exception; } } // Usage example of the previously defined DIC to get a reference // to the database connection of app1 // Set valid application context DIC::strCurrentApplication = “app1”; objDatabaseConnection = DIC::ConnectDatabase(); // objDatabaseConnection now contains a DB connection of app1 // without having seen its credentials (as the DIC is the only source of trust) |
By using this structure, you can put any dependency into your container and easily request the same.
Most of this explanation is also available as a presentation.
0 Comments.