Thursday, September 13, 2012

A Design pattern to avoid if-else ladder


Did you ever wrote a code that is having a long if else ladder? and did you ever thought of avoiding it? I am sure you would have written if else ladders atleast once. So what is wrong with it? Nothing special, one time I had to review a code that was having miles long if-else ladder and after scrolling so much and reviewing the code I had to put a plaster on my right hand index finger. [just kidding :) ]

Ok, I am not talking too much about it. I have a design pattern to avoid if else ladder in certain situations. Note that there are other situations where this approach will not work.

Problem: Assume the situation of construct an Object from an xml file or similar structure. Normally we may create an object with the required attributes and then write an xml parser to parse the xml and construct the object using setter methods for example,

XML
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<firstname>Sajith</firstname>
<lastname>Sajith</lastname>
<address>Sajith</address>
</employee>

Java code

public class Employee {

private String firstName = null;
private String lastName = null;
private String address = null;

public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

public class EmployeeParser {

public Employee parseXMLForEmployee() {
try {
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
doc = db.parse(is);

NodeList emplchilds = rootDoc.getElementsByTagName("employee").item(0).getChildNodes();
int size = emplchilds.getLength();
Employee emp = new Employee();
for(int i=0; i
Node node = emplchilds.item(i);
if (node.getNodeName().equals("firstname")) {
emp.setFirstName(node.getNodeValue());
}else if (node.getNodeName().equals("lastname")) {
emp.setLastName(node.getNodeValue());
}else if (node.getNodeName().equals("address")) {
emp.setAddress(node.getNodeValue());
}
}

return emp;
}catch(Exception e) {
}
}
}

Note that in the above code, the if-else ladder inside the for loop grows directly proportional to the number of child elements in employee node. This type of situations you can follow the below approach to solve the problem.

General Steps:
1. Create a BeanAttribute class that will have generic method for setter and getter
2. Create your java bean from inherting the BeanAttribute class. Define your specific getter and setter methods, but instead of using private member variables use the BeanAttribute class to maintain the member values.
3. then from the XML Parser use the generic setter methods to construct the bean.

See below example

public class BeanAttribute {
private HashMap attributes = new HashMap(3);

public void setAttribute(String key, String value) {
attributes.remove(key);
attributes.put(key, value);
}

public String getAttribute(String key) {
return attributes.get(key);
}
}

public class Employee extends BeanAttribute  {

public String getFirstName() {
return getAttribute("firstname");
}
public void setFirstName(String firstName) {
setAttribute("firstname", firstName);
}
public String getLastName() {
return getAttribute("lastname");
}
public void setLastName(String lastName) {
setAttribute("lastname", lastName);
}
public String getAddress() {
return getAttribute("address");
}
public void setAddress(String address) {
setAttribute("address", address);
}
}

And in the xml parser you can use;

public class EmployeeParser {

public Employee parseXMLForEmployee() {
try {
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
doc = db.parse(is);

NodeList emplchilds = doc.getElementsByTagName("employee").item(0).getChildNodes();
int size = emplchilds.getLength();
Employee emp = new Employee();
for(int i=0; i
Node node = emplchilds.item(i);
emp.setAttribute(node.getNodeName(), node.getNodeValue());
}

return emp;
}catch(Exception e) {
}
}
}

Note that the above code can handle any number of XML child elements. You need to worry about adding the required setter getter methods in the Employee class.

njoy
Sajith

1 comment:

Unknown said...


It was Nice post and very useful information
SAP Remote Online Access