Sonntag, 14. Oktober 2012

Armed against breaking Liskov

Software is generally based on contracts which are declared by interfaces and abstract base classes. The danger in OOP is to break the Liskov Substitution Principle (LSP) during implementing a contract in a class hierarchy. We remember: Liskov provides the correct way to implement subtyping without "the must" to modify classes during extending the class hierarchy. This is only the short version of the story. We know that Liskov has a deeper sight which describes the expected behaviour of subclasses in relationship to their base classes. Extensions of a class hierarchy are a cornerstore of OOP which is based on inheritance and ploymorphism. Therefore, be careful at design time of a class hierarchy by following Liskov.

There are several solutions to avoid breaking Liskov. The first solution is to use delegate instead of inheritance. Favour Composition over Inheritance (FCoI) is  the proper CCD principle for this case. Another practical way to ensure that Liskov is satisfied is to use Design By Contract (DBC) which is not a CCD principle. In the CCD community we discussed hard whether DBC should be part of the CCD universe. The Result of the discussions was that DBC is not a typical CCD  principle these days. The pronounciation lays on “these days”. The range of opinions were from "we need DBC at runtime to ensure the correct implementation of contracts" to "DBC is not necessary since we use Unit-Tests in combination with agile methods (TDD) in the software development process". My personal opinion was and still is that DBC is worth to be a CCD principle. With  a DBC framework on board the conditions to fulfill a contract are expressed at runtime (such as during testing) which in my opinion is a honest benefit. 

Anyway, DBC helps to avoid Liskov violation using preconditions, postconditions and invariants. If you think about conditions you’ll notice that preconditions are requirements to the user of a method, while the postconditions are the requirements to the method themselves.

The simple way to avoid breaking Liskov is to use inheritance in combination with design patterns. Template Method is the pattern that provides a useful constraint in subtyping. Errors during subtyping may occur by overriding concrete methods and forgetting calling the parent method. Another interesting subject is that the Template Method Pattern helps to avoid duplication (DRY). To avoid duplication is important to reduce the danger of messy software. Template Method Pattern is the vehicle during refactoring software to eliminate duplication which is a strong part of the TDD mantra.

With the Template Method Pattern we do not override a concrete method. Instead we implement a method as a template in the base class and let the subclass decide whether to implement the method or not. This technique helps us to avoid breaking Liskov. Therefore, the Template Method Pattern can be treated as an aid against breaking Liskov.

Simple class hierarchy implementing the Template Method Pattern:

abstract class Cooking {
   
    /**
     * No Source code duplication.
     * Let the subclasses decide the cooking strategy.
     */
    public void prepareMeal() {
       
        // buy food
        // prepare food
        cook();
        // serve food
    }
   
    protected abstract void cook();
}

class CookInOven extends Cooking {

    @Override
    protected void cook() {/* in oven */}
}

class CookOnGrill extends Cooking {

    @Override
    protected void cook() {/* on grill */}
}

class CookingBean {

    public void prepareMeal(final Cooking cooking) {
      
        cooking.prepareMeal();
    }
}


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.

Sonntag, 7. Oktober 2012

Builder Factory

A common problem is to initialize Java Collections within the builder pattern. The combination of the builder and the factory pattern solves this problem. Remember that the builder separates the construction of an object from its representation. The builder can therefore create objects which are variable initialized. The builder gives greater control over the construction process and isolates the construction code from the representation. This is easy in case of simple attribute types, but not for collections.

Collections have to be created first to store objects during the initialization process. Java inner classes support the isolation requirements of the creation process which is implemented in the builder. Isolation is one of the important principles of object oriented programming and often mentioned as a key principle of clean code. Why? The answer is simple: Isolation gives you the possibility to test your code.

The general rule is that only isolated loosely coupled objects are ready for testing. This rule is even more important whenever you start not with TDD which means you write your test code later. This is not the usual case but possible when the development team is separated from the test team. Take care and implement loosely coupled objects which are chained via Dependency Injection (DI) which is a principle integrated in the Java EE Standard as well as frameworks like Spring.

 Builder Factory Implementation:

import java.util.ArrayList;
import java.util.List;

public class BuilderFactoryBean {

    private final ItemBean itemBean;

    public BuilderFactoryBean(final Instance builderFactory) {
       
        itemBean = builderFactory.itemBean;
    }
   
    static class Instance {
       
        private final ItemBean itemBean = new ItemBean();
       
        public Instance cid(final String cid) {          
              
            itemBean.setCid(cid);
           
            return(this);
        }
       
        public Instance item(final String listItem) {          
                       
            initializeItemList();
           
            addItem(listItem);
           
            return(this);
        }

        private void initializeItemList() {
           
            if(null == itemBean.getListItems()) {
           
                final BuilderFactory<String> factory = new BuilderFactory<String>() {
   
                    @Override
                    public List<String> create() {
                       
                        return new ArrayList<String>();
                    }                   
                };
               
                itemBean.setListItems(factory.create());
            }
        }
       
        private void addItem(final String listItem) {
           
            itemBean.getListItems().add(listItem);
        }
       
        public BuilderFactoryBean build() {
           
            return(new BuilderFactoryBean(this));
        }
       
        private interface BuilderFactory<T> {
           
            public List<T> create();
        }
    }
   
    public ItemBean getItemBean() {
   
        return itemBean;
    }
}

 Item Bean:

import java.util.List;

public class ItemBean {

    private String cid;
    private List<String> listItems;

    public String getCid() {
        return cid;
    }

    public void setCid(String cid) {
        this.cid = cid;
    }

    public List<String> getListItems() {
        return listItems;
    }

    public void setListItems(List<String> listItems) {
        this.listItems = listItems;
    }

    @Override
    public String toString() {
       
        final StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("cid=");
        strBuilder.append(cid);
       
        for(String listItem : listItems) {   
           
            appendItem(strBuilder, listItem);
        }
       
        return strBuilder.toString();
    }

    private void appendItem(final StringBuilder strBuilder, final String listItem) {
       
        strBuilder.append(",");
        strBuilder.append("item=");
        strBuilder.append(listItem);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((cid == null) ? 0 : cid.hashCode());
        result = prime * result
                + ((listItems == null) ? 0 : listItems.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ItemBean other = (ItemBean) obj;
        if (cid == null) {
            if (other.cid != null)
                return false;
        } else if (!cid.equals(other.cid))
            return false;
        if (listItems == null) {
            if (other.listItems != null)
                return false;
        } else if (!listItems.equals(other.listItems))
            return false;
        return true;
    }
}

 Builder Factory Test:

import org.junit.Assert;
import org.junit.Test;

public class BuilderFactoryBeanTest {

    @Test
    public void testBuilderFactory()  {
       
        final BuilderFactoryBean firstBuilderFactory = new BuilderFactoryBean.Instance().cid("cid-1").
                                                                                         item("item-1").item("item-2").build();
       
        final BuilderFactoryBean secondBuilderFactory = new BuilderFactoryBean.Instance().cid("cid-1").
                                                                                          item("item-1").item("item-2").build();
       
        Assert.assertEquals(firstBuilderFactory.getItemBean(), secondBuilderFactory.getItemBean());
    }
}



Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.