Saturday, October 10, 2009

refactoring my code (with a little help from my friend Eclipse)

In this post, I'll explain few refactoring tricks and we will use the help of Eclipse as much as possible. Here we go!



Map<String, List<String>> personalItemsMap = new HashMapMap<String, List<String>>();

// for darth vader

List<string> vaderList = new ArrayList<string>();
vaderList.add("lightsaber");
vaderList.add("helmet");
vaderList.add("armor");
personalItemsMap.put("darth vader", vaderList);

// for han solo
List<string> soloList = new ArrayList<string>();
soloList.add("blaster");
soloList.add("vest");
personalItemsMap.put("han solo", soloList);

// for boba fett
List<string> bobaList = new ArrayList<string>();
bobaList.add("blaster");
bobaList.add("mandalorian armor");
personalItemsMap.put("boba fett", bobaList);

System.out.println(personalItemsMap);







Above we create a list of items for each character and add them to an owner-item map. This piece of code is begging for refactoring.



First, I choose the piece of code I'd like to extract as a method.



Then I choose refactor>extract method.


I enter "generateVaderList" as method name and here's our refactored code.


public static void main(String[] args) {
Map<String, List<String>> personalItemsMap = new HashMap()<String, List<String>>;

// for darth vader
List<string> vaderList = createVaderList();
personalItemsMap.put("darth vader", vaderList);

// for han solo
List<string> soloList = new ArrayList<string>();
soloList.add("blaster");
soloList.add("vest");
personalItemsMap.put("han solo", soloList);

// for boba fett
List<string> bobaList = new ArrayList<string>();
bobaList.add("blaster");
bobaList.add("mandalorian armor");
personalItemsMap.put("boba fett", bobaList);

System.out.println(personalItemsMap);
}

private static List createVaderList() {
List vaderList = new ArrayList();
vaderList.add("lightsaber");
vaderList.add("helmet");
vaderList.add("armor");
return vaderList;
}


No need for a temporary reference assignment so I can edit the below part;


List<string> vaderList = createVaderList();
personalItemsMap.put("darth vader", vaderList);


to


personalItemsMap.put("darth vader", createVaderList());


If I do this refactoring for every character my code will be clearer. But think about it. If I do that I'll have three different methods with similar functionality. These methods create a list, add necessary elements to the list and return the list. What if I take these methods and write a more generic one instead of three methods with similar functionality? Later, if I'd like to add a new character I won't write a createNewCharacterList method. I'll use the generic one instead.

Lets see how we can make the method more generic. It creates a list and adds hard-coded strings to it. This method will be general if I hand it the item strings to add. First I choose the name of "createVaderList" and then right click. Then refactor>rename. I rename it as "createItemList". I'm writing a more general method, remember? I can change the method signature from the menu but this is not so handy so I'll skip that and edit my method by hand.


private static List createItemList() {
List<string> vaderList = new ArrayList<string>();
vaderList.add("lightsaber");
vaderList.add("helmet");
vaderList.add("armor");
return vaderList;
}


will become


private static List<string> createItemList(String... items) {
List<string> itemList = new ArrayList<string>();

for(String item : items)
itemList.add(item);

return itemList;
}


In this new method, we -again- create a list. Then we take an arbitrary number of strings. I assure this behavior by using var-args. Then in our beautiful for-loop we add the items to the item list and return the list.

After that we will do the necessary changes in the code. Eclipse can't help us in this case. After we do the necessary changes in our code, our main method will be such as below;


public static void main(String[] args) {
Map<String, List<String>> personalItemsMap = new HashMapMap<String, List<String>>();

// for darth vader
personalItemsMap.put("darth vader", createItemList("lightsaber", "helmet", "armor"));

// for han solo
personalItemsMap.put("han solo", createItemList("blaster", "vest"));

// for boba fett
personalItemsMap.put("boba fett", createItemList("blaster", "mandalorian armor"));

System.out.println(personalItemsMap);
}


Much clearer and more usable right?

No comments:

Post a Comment