Browse DevX
Sign up for e-mail newsletters from DevX


Design Better Software with the Inversion of Control Pattern : Page 2

The Inversion of Control pattern facilitates reuse, loose coupling, and easy testing of software components. Learn how to use it in your software design.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

IoC Frameworks
Several open source IoC frameworks like Spring, PicoContainer, and HiveMind support the IoC pattern. While the general IoC principle is simple, each of these frameworks supports different implementations and offers different benefits. The IoC pattern can be implemented in three ways: setter based, constructor based, and interface based. This section briefly discusses each of them. For more in-depth details, refer to the frameworks' home pages.

Setter-Based IoC
This type of IoC uses a setter method to inject the referenced object into a referring object. This is the most common type of IoC, and both Spring and PicoContainer implement it. Setter-based IoC is good for objects that take optional parameters and objects that need to change their properties many times during their lifecycles. Its main disadvantage is that you need to expose all the properties of an object to the outside world when using a setter method. This breaks one of the key OO principles: data encapsulation and information hiding.

Constructor-Based IoC
This type of IoC uses a constructor to set the reference of the object. Its main advantage is that only the creator knows about the referenced object. Once the object is created, the client code that uses the object is unaware of the referenced object. This approach may not work in all types of applications, however. For example, if you use an external API that needs a default constructor, then you need to go with a setter-based IoC. A constructor-based IoC is the main type of implementation in Spring.

Interface-Based IoC
In this type of IoC, objects implement a specific interface from the IoC framework, which the IoC framework will use to properly inject the objects. One of the main advantages of this type is that it doesn't need an external configuration file to configure the object references. Since you need to use the IoC framework's marker interface, the IoC framework knows how to glue the objects together. It is similar to using EJB. Any EJB container knows how to instantiate your objects and hook them with itself. The main disadvantage of this approach is that the marker interface ties your application to a specific IoC framework. Apache Avalon is based on this approach but this project has been closed.

An Example of IoC
If you are starting a new project, you can choose any of the open source IoC frameworks based on your needs. If you want to use the IoC pattern in your existing project then you need to write your own classes that support IoC. Though the open source frameworks offer off-the-shelf components and may provide many more features than your own implementation, you can still develop a set of classes that support the IoC pattern. This section demonstrates how.

Say you want to write a CustomerService object to process customer data. Assume customer data is stored in two different places: a relational database and an XML file. You also want to have CustomerService create Customer objects by reading data from either the database or the XML file. Now, say you want to accomplish this without changing the source code of CustomerService to switch between the database and XML file.

First, design an interface (see Listing 4) and define common methods, which you will use to retrieve and store customer data. Both XMLDataSource and JDBCDataSource classes implement this interface.

public interface DataSource { public Object retrieveObject(); public void setDataSourceName(String name); public String getDataSourceName(); public void storeObject(Object object); } Listing 4. Common Interface to Customer Data

Listing 5 shows a class that implements DataSource and provides an implementation that uses an XML file to retrieve and store customer data.

public class XMLDataSource implements DataSource { private String name; /** * Default Constructor */ public XMLDataSource() { super(); } /** * Retrieve Customer data from XML Source and construct * Customer object */ public Object retrieveObject() { //get XML data, parse it and then construct //Customer object return new Customer("XML",10); } /** * Set the DataSource name */ public void setDataSourceName(String name) { this.name=name; } /** * Return DataSource name */ public String getDataSourceName() { return name; } /** * Store Customer into XML file */ public void storeObject(Object object) { //Retrieve customer data and store it in //XML file } } Listing 5. Class to Retrieve Customer Data from XML File

The class in Listing 6 also implements DataSource and provides the same implementation as XMLDataSource with only one difference: this class retrieves and stores customer data using a relational database.

public class RelationalDataSource implements DataSource { private String name; /** * Default constructor */ public RelationalDataSource() { super(); } /** * Using the DataSource retrieve data for Customer and build a * Customer object to return it to the caller */ public Object retrieveObject() { //get data for Customer object from DB and create a //Customer object return new Customer("Relational",10); } /** * Set the DataSource name */ public void setDataSourceName(String name) { this.name=name; } /** * Return the name of the DataSource */ public String getDataSourceName() { return name; } /** * Store Customer into relational DB */ public void storeObject(Object object) { //store the customer data into Relational DB } } Listing 6. Class to Retrieve Customer Data from Relational DB

Thanks for your registration, follow us on our social networks to keep up-to-date