Browse DevX
Sign up for e-mail newsletters from DevX


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

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

The simple class in Listing 7 holds customer data, which either the XMLDataSource or RelationalDatSource object will construct.

public class Customer { private String name; private int age; /** * Default Constructor */ public Customer(String name, int age) { this.name=name; this.age=age; } /** * @return Returns the age. */ public int getAge() { return age; } /** * @param age The age to set. */ public void setAge(int age) { this.age = age; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } } Listing 7. Class That holds Customer Data

This class in Listing 8 has a reference to DataSource, which it uses to retrieve and store Customer objects. The actual implementation of DataSource will be either XMLDataSource or RelationalDataSource, which will be injected into the CustomerService object. The constructor of the CustomerService object accepts a concrete implementation of the DataSource object and uses it to retrieve and store customer data.

public class CustomerService { private DataSource dataSource; private Customer customer; /** * Constructor in which DataSource object is injected. Based on the * ioc.properties this object can either refer to RelationlDataSource or * XMLDataSource */ public CustomerService(DataSource dataSource) { super(); this.dataSource=dataSource; customer=(Customer)dataSource.retrieveObject(); } /** * Modify Customer name * @param name */ public void updateCustomerName(String name) { customer.setName(name); } /** * Modify Customer age * @param age */ public void updateCustomerAge(int age){ customer.setAge(age); } /** * * @return Customer name */ public String getCustomerName(){ return customer.getName(); } /** * * @return Customer age */ public int getCustomerAge(){ return customer.getAge(); } } Listing 8. CustomerService Class That Gets DataSource Reference via ServiceConfigurator

Figure 4. IoC Using ServiceConfigurator

The ServiceConfigurator in Listing 9 is a main class that uses the IoC pattern to inject the concrete implementation of DataSource into the CustomerService object. It reads the configuration parameters (see Figure 4) from the ioc.properties file and decides to create either an XMLDataSource or a RelationalDataSource object. The DataSource object is created using its default Constructor, and the name of the DataSource is set using its setter method. The created DataSource object is injected into CustomerService using its constructor, which accepts a DataSource reference. The created CustomerService object is stored in the ServiceConfigurator registry so that it will be returned when a subsequent request comes for the CustomerService object.

Figure 4 shows the inner workings of ServiceConfigurator, and Figure 5 shows the UML diagram for all of the classes explained previously. You can switch between XMLDataSource and RelationalDataSource just by editing the ioc.properties file.

public class ServiceConfigurator { public static final String IoC_CONFIG_FILE="ioc.properties"; private Properties props; private HashMap serviceRegistery; private static ServiceConfigurator thisObject; /** * This method first checks if there is a ServiceConfigurator instance * exist, if not creates a one, stored it and returns it * @return */ public static ServiceConfigurator createServiceConfigurator(){ if(thisObject==null){ thisObject=new ServiceConfigurator(); } return thisObject; } /** * Private Constructor makes this class singleton */ private ServiceConfigurator() { props = new Properties(); serviceRegistery=new HashMap(); loadIoCConfig(); createServices(); } /** * Load the IoC_CONFIG_FILE properties file * */ public void loadIoCConfig(){ InputStream is = this.getClass().getClassLoader().getResourceAsStream(IoC_CONFIG_FILE); try { props.load(is); is.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Create the CustomerService by getting the DataSource name from the * properties file. The CustomerService object is stored in the * serviceRegistery so that it will be retrieved when requested. * During the construction of CustomerService the DataSource object * is injected into it. So the CustomerService can access the DataSource * to retrieve the Customer. * */ public void createServices(){ String dataSourceName=props.getProperty("dataSource"); DataSource dataSource=null; if(dataSourceName!=null){ try { dataSource=(DataSource)Class.forName(dataSourceName).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //name of the DataSource is retrieved from the properties file dataSource.setDataSourceName(props.getProperty("name")); CustomerService customerService=new CustomerService(dataSource); serviceRegistery.put(CustomerService.class,customerService); } /** * Stored Service is retrieved from serviceRegistery for the given * Class object * * @param classObj * @return */ public Object getService(Class classObj){ return serviceRegistery.get(classObj); } } Listing 9. ServiceConfigurator that Uses IoC to Inject DataSource into CustomerService

Figure 5. ServiceConfigurator UML Class Diagram

The ServiceConfigurator is a simple class that supports the IoC pattern. You can modify it to add more features such as simultaneously supporting multiple DataSource objects, dynamically injecting the DataSource into CustomerService, and life cycle management.

The class in Listing 10 is a JUnit test that uses CustomerService. It uses ServiceConfigurator to retrieve the CustomerService object, which is used to change the Customer name and age.

public class CustomerServiceTester extends TestCase{ private ServiceConfigurator serviceConfig; /** *Default Constructor */ public CustomerServiceTester() { super(); } /** * Create ServiceConfigurator */ public void setUp() throws Exception{ super.setUp(); serviceConfig=ServiceConfigurator.createServiceConfigurator(); } /** * Test CustomerService and check for Customer * @throws Exception */ public void testCustomerService() throws Exception{ CustomerService custService=(CustomerService)serviceConfig.getService(CustomerService.class); assertNotNull(custService); custService.updateCustomerAge(30); custService.updateCustomerName("Mani"); assertEquals(30,custService.getCustomerAge()); assertEquals("Mani",custService.getCustomerName()); } Listing 10. JUnit Test that Uses CustomerService

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