Home > Java, Uncategorized > Refactoring simple code

Refactoring simple code

In this essay I’ll be outlining and exposing some of the approaches, thought processes & strategies I engage in when refactoring code. I’ll continue with some of the very simple themes outlined in Fun with String vectors… Part 1.Let’s say we now want to add two String vectors (usually derived from String arrays) together…. It’s something I often have to do when handling blocks of multiline text…

public  Vector<String> joinVectors(Vector<String> v1, Vector<String> v2)
{
Vector<String> vOutput = getPreparedVector();
vOutput.addAll(v1);
vOutput.addAll(v2);
return vOutput;
}

Easy enough. But I think you’ll agree that a lot of this vector activity is more geared to action surrounding the vector or array being handled than the String replacement class and probably really belongs in a class of its own. So at this point we might seriously think about refactoring and moving the Vector action to a StringVector class. The upshot of this is that we might also want to do similar sorts of things for all the other collection classes which we might be using to operate on Strings with. It also occurs to me that a lot of this sort of activity is not only pertinent to Strings but might equally well apply to Integers and all other non-primitive types which we might want to work on, e.g. Integers, Longs, etc. We will probably want to supply an interface to ensure conformity across our proposed StringVector class and, say, an IntegerVector class or a LongVector class.

The first and immediately obvious candidate for refactoring from previously is the method with the signature public Vector getPreparedVector(), a neutral enough name.

The next is the vectorToStringArray( Vector v ) , however it might appear as if semantics is going to be an issue here because we will want this method signature’s name to be applicable to all the other Objects we may need classes for (e.g. we are going to be deeply confused calling IntegerVector.vectorToStringArray()), so first off we could neutralise this by renaming it to vectorToArray. However, it should be apparent to you that vectorToArray(Vector v) is less a function of a Collection class than a generic Array replacement class, which we might putatively name ArrayMaster, where it will live with similar methods which will produce different types of arrays… for example an Integer array. In an ideal world this would present no problem but of course Java doesn’t recognise overloading on return values and two identically named methods will result in Java or your IDE notifying you that the overloaded method with the different return signature is already defined in the class. So.. The simple thing is to have one uniquely named method per Object type, i.e. vectorToIntegerArray, vectorToLongArray etc.

The other thing we might have liked to consider is to produce a method with the signature public Object[] vectorToArray(Vector v). However this won’t fly since you can’t cast a Java supertype Array into a subtype, and if you attempt to compile it you would get a ClassCastException, the reason being that every element would need to be examined by the JVM for type safety. (The rules for this can be found here: http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#20232). So it’s back to the drawing board with discretely named methods vectorToStringArray, vectorToIntegerArray, vectorToLongArray etc.

We can however make these Array conversion utilities simpler by refactoring the code a tad and taking advantage of Vector’s toArray() method e.g. from :

/**
* Will convert a passed vector to a string array
* @param Vector v - the vector for conversion
* @return String array of the converted vector
*/
public String[] vectorToStringArray( Vector<String> v )
{
int count = v.size();
String[] outArray = new String[count];
v.copyInto(outArray);
return outArray;
}

to:

/**
* Will convert a passed vector to a string array
* @param Vector v - the vector for conversion
* @return String array of the converted vector
*/
public String[] vectorToStringArray(Vector<String> v)
{
return (String[])v.toArray(new String[v.size()]);
}
// and our new Integer component.....
/**
* Will convert a passed vector to a integer array
* @param Vector v - the vector for conversion
* @return Integer array of the converted vector
*/
public Integer[] vectorToIntegerArray(Vector<Integer> v)
{
return (Integer[])v.toArray(new Integer[v.size()]);
}

[..]

Next up we can look at public Vector getVectorFromStringArray(String[] inArray) . The name is frankly horrible and we immediately refactor this to vectorToArray. While this is ostensibly type-agnostic, we will however want to type-check the Vector per Object type, and add one implementation per ObjectVector class, i.e. there will be a method typechecking and producing String Vectors in StringVector, Integers in IntegerVector, etc.

So we now have two obvious methods to define in our proposed vectorInterface interface, getPreparedVector and arrayToVector, which should look something like this.

import java.util.Vector;

public interface VectorInterface {
    public Vector getPreparedVector();
    public Vector arrayToVector(Object[] xArray);
}

Our new StringVector class should look something like this (I’ve removed comments, etc, for concision):

import java.util.Vector;

public class StringVector implements VectorInterface {

public  Vector<String> getPreparedVector()
{
Vector<String> vOutput = new Vector<String>();
return vOutput;
}

public  Vector<String> arrayToVector(Object[] sArray)
{
Vector<String> v = getPreparedVector();
for (int i = 0; i<sArray.length; i++)
{
v.add(sArray[i].toString());
}
return v;
}
/* Method to join two String vectors
* @param v1 vector to add to
* @param v2 vector to be added on to v1
* @return the joined vectors
*/
public  Vector<String> joinVectors(Vector<String> v1, Vector<String> v2)
{
Vector<String> vOutput = getPreparedVector();
vOutput.addAll(v1);
vOutput.addAll(v2);
return vOutput;
}

}

And our IntegerVector class will look pretty much the same with Integer substituted for String appropriately,and an Integer conversion of

v.add(sArray[i].toString()); 

to read

v.add(Integer.parseInt(sArray[i].toString()));
//or (if we can be sure of the contents of the Array)
v.add((Integer) sArray[i]);
Advertisements
  1. No comments yet.
  1. No trackbacks yet.

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: