Java Design Patterns – How to Handle Sorting of Complex Objects

design-patternsjavasorting

How would one sort a list of objects that have more than one sortable element?

Suppose you have a simple object Car and car is a defined as such:

class Car {
    public String make;
    public String model;
    public int year;
    public String color;
    // ... No methods, just a structure / container
}

I designed a simple framework that would allow for multiple SortOptions to be provided to a Sorter that would then sort the list.

interface ISorter<T> {
    List<T> sort(List<T> items);
    void addSortOption(ISortOption<T> option);
    ISortOption<T>[] getSortOptions();
    void setSortOption(ISortOption<T> option);
}

interface ISortOption<T> {
    String getLabel();
    int compare(T t1, T t2);
}

Example use

class SimpleStringSorter extends MergeSorter<String> {
    {
        addSorter(new AlphaSorter());
    }

    private static final class AlphaSorter implements ISortOption<String> {
        // ... implementation of alpha compare and get label
    }
}

The issue with this solution is that it is not easily expandable. If car was to ever receive a new field, say, currentOwner. I would need to add the field, then track down the sorter class file, implement a new sort option class then recompile the application for redistribution.

Is there an easier more expandable/practical way to sort data like this?

Best Answer

Actually you can use a comparator which has a method compare(a,b) which you can implement.

Then you can pass it in for the compare step (this is supported in nearly all standard libraries of most languages).

For example in java you can call

Collections.sort(fooList, new Comparator<Car>(){
    public int compare(Car a,Car b){
        return a.getModel().compareTo(b.getModel());
        // or compare what you want return -1, 0 or 1 
        // for less than, equal and greater than resp.
    }
});

To sort your lists according to a custom comparator

In java 8 there is a lambda syntax to create the Comparator in a single line.

This means there will be only one sorting algorithm to maintain and a bunch of comparators which can remain in the same class as what it is comparing, (or near the place where the comparing is taking place).

This also allows for a "tiered" sort, you can implement something like:

public static Comparator<T> createTieredComparator(final Comparator<? super T> comp1, final Comparator<? super T> comp2){
    return new Comparator<T>(){
        public int compare(T a,T b){
            int res = comp1.compare(a,b);
            if(res!=0)
                return res;
            else
                return comp2.compare(a,b);
        }
    };
}

This will prefer the comparison made by comp1 and only return the result of comp2 when they would be considered equal according to comp1.

Related Topic