This week I’ll tell you about inversion of control. This is very useful thing if you are going to develop dynamic application in compliance with modern approach to software development.
Spring framework gives you flexibility providing dynamical beans wiring, but for deeper understanding let’s consider principle of inversion of control beyond Spring. Look at this code:
public class Calculator {
private final DbWriter dbWriter;
public Calculator() {
// Class Calculator can't be used in DbWriter absence.
this.dbWriter = new DbWriter();
}
// Some methods in Calculator class
public final Integer opAdd(Integer a, Integer b) {
return a + b;
}
public final boolean saveResult(Integer number){
return dbWriter.saveInDb(number);
}
}
public class DbWriter {
public DbWriter(){
// code for database initialization
}
public boolean saveInDb(Integer value ){
// save value to db
// if save operation is successful return true
return true;
}
}
Code language: PHP (php)
This is an example of wrong style in designing programs, because of program will lose its flexibility. Class Calculator can’t be used independently of DBSaver class. So, what will you do if you have to change code in a short time?
Thus we have to separate classes into two (or much more in real projects) independent logical blocks called beans. Let’s to create a new interface contains methods concerned with both classes.
In a such a way we destroy dependencies between two classes and obtain possibility to choose right way to save data to db in our case.
public interface IResultSaver {
public boolean saveResult(Integer result);
}
public class Calculator {
private IResultSaver saver;
public Calculator() {
}
// Some methods in Calculator class
public final Integer opAdd(Integer a, Integer b) {
return a + b;
}
//Here you can put any instance of classes implement IResultSaver
public final void setSaver(IResultSaver saver) {
// Choose saver
this.saver = saver;
}
public final boolean saveResult(Integer resultToSave){
rerurn saver.saveResult(resultToSave)
}
}
// DB saver.
public class DbWriter implements IResultSaver {
public DbWriter() {
// code for database initialization
initializeDbConnection();
}
@Override
public boolean saveResult(Integer result) {
return saveDbOperation(result);
}
}
public class FileWriter implements IResultSaver {
public FileWriter() {
// code for database initialization
initializeFile();
}
@Override
public boolean saveResult(Integer result) {
return saveFileOperation(result);
}
}
Code language: PHP (php)
Calculator class can use any classes via interface, so we can use them in elegant manner. So everything is clear, and we can apply this principle for calculation operations like in last article. This is a nice example of inversion of control (IoS). Spring framework provides this trick using containers for creation some class instances and dependences between them in XML file.
Take a look at this code:
public interface IOperation {
public Integer operation(final Integer a, final Integer b);
}
public interface IResultSaver {
public boolean saveResult(Integer result);
}
public class Calculator {
private IResultSaver saver;
private IOperation operation;
// Spring container automaticaly sets
// beans corespond to XML conficuraion file via setters
public void setSaver(IResultSaver saver) {
this.saver = saver;
}
public void setOperation(AddBean operation) {
this.operation = operation;
}
public boolean saveResult(final Integer result) {
return saver.saveResult(result);
}
public final Integer calculate(final Integer a, final Integer b) {
return operation.operation(a, b);
}
}
// DB saver.
public class DbWriter implements IResultSaver {
public DbWriter(final String dataSourceName) {
// code for database initialization
System.out.println("Here you can initialize you db connection!"
+ dataSourceName);
}
public boolean saveResult(final Integer result) {
// code for saving result
System.out.println("This is Db saver!");
return true;
}
}
// File saver
public class FileWriter implements IResultSaver {
public FileWriter(final String filename) {
// code for database initialization
System.out.println("Initializing file writer with parameter:file name" + filename);
}
public boolean saveResult(final Integer result) {
//code for saving result
System.out.println("This is file saver!");
return true;
}
}
// Bean for add
public class AddBean implements IOperation{
public Integer operation(final Integer a, final Integer b) {
return a + b;
}
}
// Bean for multiply
public class MultiplyBean implements IOperation {
public Integer operation(final Integer a,final Integer b) {
return (Integer) a * b;
}
}
public class main {
public static void main(String args[]) {
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
Calculator calculator = (Calculator) factory.getBean("calculator");
calculator.saveResult(calculator.calculate(2, 2));
}
}
Code language: PHP (php)
This is pretty sample of Inversion of control using Spring framework. Spring container hides creation of instances of correspond beans, and we obtain dynamic application. Configuration information for container contains XML file and you can change during execution of your application.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://springframework.org/schema/beans
http://springframework.org/schema/beans/spring-beans.xsd">
<!--IOperation beans-->
<bean name="add" class="InversioOfControl.AddBean"/>
<bean name="mul" class="InversioOfControl.MultiplyBean"/>
<!--IResultSaver beans-->
<bean name="db" class="InversioOfControl.DbWriter">
<constructor-arg value="yourDataSource"/>
</bean>
<bean name="file" class="InversioOfControl.FileWriter">
<constructor-arg value="fileForSave.txt"/>
</bean>
<!-- Here we describe calculator bean contains two props -->
<bean name="calculator" class="InversioOfControl.Calculator">
<property name="saver" ref="db"/>
<property name="operation" ref="add"/>
</bean>
</beans>
Code language: HTML, XML (xml)
So user can choose beans dynamically, during program execution. User has to change names of beans in property fields.