Refactoring hierarchy construction

Lets introduce *Settings classes hierarchy:

settingsHierarchy

Settings hierarchy

And here is how our original hierarchy has changed:

Refactored hierarchy

Refactored hierarchy

Here is the code for settings hierarchy:

public class AbstractBaseSettings {

    public AbstractBaseSettings(Object field1, Object field2) {
	this.field1 = field1;
	this.field2 = field2;

	if (!validateFields())
	    throw new IllegalArgumentException(
		    "Invalid fields passed to constructor");
    }

    public boolean validateFields() {
	// ...
	// validate field1 and field2 here

	return true;
    }

    Object field1;
    Object field2;
}

public class ConcreteClass2Settings extends AbstractBaseSettings {

    public ConcreteClass2Settings(Object field1, Object field2, Object field5,
	    Object field6) {
	super(field1, field2);

	this.field5 = field5;
	this.field6 = field6;
    }

    @Override
    public boolean validateFields() {
	boolean result = false;

	if (super.validateFields()) {
	    // ...
	    // validate field5 and field6 here
	}

	return result;
    }

    protected Object field5;
    protected Object field6;
}

...

And here are our business classes:

public abstract class AbstractBase implements IBase {

    protected AbstractBase(AbstractBaseSettings settings) {

	this.settings = settings;

	if (settings == null)
	    throw new IllegalArgumentException(
		    "Settings parameter passed to constructor is null");
    }

    @Override
    public void foo2() {
	// dowork
    }

    protected AbstractBaseSettings settings;
}

public class ConcreteClass2 extends AbstractBase {

    protected ConcreteClass2(ConcreteClass2Settings settings) {
	super(settings);

	if (settings == null)
	    throw new IllegalArgumentException(
		    "Settings parameter passed to constructor is null");
    }

    @Override
    public void foo() {
	// ...
	// provide concrete implementation of foo() here
    }

}

...

As you can see we’ve accomplished several goals:

1. Moved all validation logic away from ┬ábusiness objects. Now each concrete implementation works as it was originally designed – performs some actions on data using foo() and foo2() methods. And all validation of initial data used for cunstruction of our business objects has moved into separate classes.

This is a great example of high cohession GRASP pattern. Each object performs clear, dedicated and precise action.

2. Refactored constructors and greatly improved readability.

3. Resolved and simplified unit testing issues. Now we can test validation logic and business logic separately

4. Improved usability. In order to construct business object user must provide *settings instance ( sublass of AbstractBaseSettings class). In order to construct *settings object the valid input data should be provided or IllegalArgumentException will be thrown.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: