Should it know that information

By on Jun 9, 2013 in eng | 0 comments

Share On GoogleShare On FacebookShare On Twitter

A couple sprints ago I did a small refactoring on a piece of code. The code is short but able to clearly express the concept of distributing knowledge between objects. Again, I can’t put the real code here so I will use example classes that still preserve the main details and usage scenario.

I have Field class which, for now, nothing more than a value object holding a string of field value. Then I have a FieldSet class to hold a set of fields. It is a good practice to create an abstraction for a collection of data since the system tends to grow in the way that we will need to add some behaviors to the collection. Instead of passing around Set object, The FieldSet is used to encapsulate the collection and act as a new abstraction which we could add some methods to it in the future.

public class FieldSet implements Iterable{

	private Set fields = new HashSet();

	public void addField(String fieldName){
		fields.add( new Field(fieldName));
	}

	@Override
	public Iterator iterator() {
		return Collections.unmodifiableSet(fields).iterator();
	}
}

public class Field {
	private String fieldValue;

	public Field(String value){
		this.fieldValue = value;
	}

	public String getValue(){
		return this.fieldValue;
	}
}

Then there is a requirement that the field in the collection need to be sorted. So the FieldSet has been revised to use sorted collection with a custom comparator.

private Set fields = new TreeSet(new Comparator() {
	@Override
	public int compare(Field fiedl1, Field field2) {
		return fiedl1.getValue().compareTo(field2.getValue() );
	}
});

At first, it is quite natural to add the comparator in the FieldSet class. The train of thought is that the class contains a set of filed and then the set need to be sorted so the comparator is put to the set’s constructor here. The problem is that the comparator need to know how to compare the Field objects. If the Field class has been changed to support new member variable that should be included in the sorting then we have to change this comparator. That means the change in Field class will also introduce the change in FieldSet class. We called this dependency relationship “coupling”.

Object oriented encourages the use of object that put the data and the operations on that data together in one place. The Field class contains the data so it should be the one who knows best how to sort the data. To put it even more obvious, the Field should know how to sort itself. We can achieve this by making the class implement Comparable interface. Now we can remove the comparator passed to the constructor of TreeSet.

public class Field implements Comparable{
	private String fieldValue;

	//… unchanged code …

	@Override
	public int compareTo(Field otherField) {
		return this.fieldValue.compareTo( otherField.fieldValue );
	}
}

Another point is less obvious but still falls into the same pattern. The method to add new Field to the FieldSet is trying to know too much.

public void addField(String fieldName){
fields.add( new Field(fieldName));
}

It meant to provide callers a convenient way to add a new Field. Again, the coupling between two classes will make the change in Field’s constructor cause the need to change in this method. The FieldSet should not know too much on how to create a Field object. It should just know how to add Field object to it collection.

	public void addField(Field field){
		fields.add( field );
	}

Submit a Comment

Your email address will not be published. Required fields are marked *