Introduction

This is the second and final part of a very simple re-factoring project. It shows how a few simple things can massively improve the code.

Installing Junit using Maven

Not much happening in this project with tests as I have just realised how out of date junit 3.anything is. To grab junit, simply add the following to the pom.xml file and if your IDE doesn’t reload the dependencies automatically, manually reload them.

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Writing the test

There is only one test in this project and because of the size, it doesn’t give much advantage over manually running the code. However, it does show the concept. In the next, larger, project I’ll move to JUnit 5 and make much more use of them.

package com.thefifthcontinent.sort;

import junit.framework.TestCase;

import java.util.Arrays;

public class SortTest extends TestCase {

    public void testRipple() {

        int data[] = {14, 12, 19, 7, 4, 1};
        int sorted[] = {1, 4, 7, 12, 14, 19};

        Sort sorter = RippleSort.newInstance();
        sorter.sort(data);

        assertEquals(Arrays.toString(sorted), Arrays.toString(data));
    }
}

Renaming variables

Simply renaming a few variables makes the code far easier to read and understand. The variable d becomes toBeSorted , s becomes swapPerformed and i changes to currentItem. As you can see, what the variables are for is instantly clear.

Code to an interface

Best practice is to code to an interface, this means that where possible, you should code to a more generic type allowing different parts of the code to be decoupled. Note that coding to an interface does not mean only using an Interface. You can use an abstract or concrete parent class also.

In this project, we may need to use different sort algorithms so we’ll create an abstract Sort class which our concrete classes can extend.

package com.thefifthcontinent.sort;

public abstract class Sort {

    public abstract void sort(int[] toBeSorted);

    final boolean swap(final int[] toBeSorted, final int currentItem) {

        if (toBeSorted[currentItem] > toBeSorted[currentItem+1]) {
            int temp = toBeSorted[currentItem];
            toBeSorted[currentItem] = toBeSorted[currentItem+1];
            toBeSorted[currentItem+1] = temp;
            return true;
        }

        return false;
    }
}

Moving sort code to a specific class

The implementation of the ripple sort is moved into its own class which is very simple. It extends Sort and implements the sort method. You’ll notice how the code to carry out the actual swapping of the array elements has been moved into the parent class so that it can be shared by all implementations. this helps our code adhere to the DRY principle.

package com.thefifthcontinent.sort;

public class RippleSort extends Sort {

    public static RippleSort newInstance() {
        return new RippleSort();
    }

    final public void sort(final int[] toBeSorted) {

        boolean swapPerformed = false;

        do {

            for (int currentItem=0; currentItem<toBeSorted.length -2; currentItem++) {
                swapPerformed = swap(toBeSorted, currentItem);
            }

            if (!swapPerformed) {
                break;
            }

            for (int currentItem=toBeSorted.length -2; currentItem>-0; currentItem--) {
                swapPerformed = swap(toBeSorted, currentItem);
            }

        } while(swapPerformed);
    }

    private RippleSort() {}
}

The main class is now also very simple.

package com.thefifthcontinent;

import com.thefifthcontinent.sort.RippleSort;
import com.thefifthcontinent.sort.Sort;

public class Main {

    public static void main(String[] args) {

        int data[] = {14, 12, 19, 7, 4, 1};

        report("Before", data);

        final Sort sorter = RippleSort.newInstance();
        sorter.sort(data);

        report("After", data);

    }

    private static void report(final String when, final int[] data) {
        System.out.println(when + ": ");
        for (int item : data) {
            System.out.print(item + " ");
        }
        System.out.println();
    }
}

Immutability

Where possible, define methods and variables as final as it stops them from being changed unexpectedly and improves the robustness and security of the software. The interesting line is final public void sort(final int[] toBeSorted) { which allows the array contents to be modified but not the array itself.

Links

Code repository