Skip to main content

Using the Strategy Design Pattern for Sorting POJOs

April 7, 2005

{cs.r.title}









Contents
What Will We Sort?
First Implementation
Second Implementation
Applying the Strategy Design Pattern
Afterword
Resources

I wouldn't be exaggerating if I said that all of us use POJO's—"Plain Old Java Objects"— in our everyday
application development. We use them with Hibernate or with entity beans, sometimes we use them as simple transfer (value) objects,
and we use them while creating domain models.

But what is POJO itself? This term appeared not so long ago and was
credited to Martin Fowler, who provides his own
explanation
of POJO
. You can think of POJO as a fancy name denoting
a normal Java object that is not a JavaBean, an entity bean, or a
session bean, and does not serve any other special role or
implement any special interfaces of any of the Java frameworks.

Many people on discussion forums have asked how to sort POJOs
using only core J2SE, since Java provides an excellent way to sort
small amounts of data. For larger data-sorting tasks, especially
with data that has been extracted from a database, it is more
efficient to make the database perform the sort in the first
place. However, that discussion goes beyond the scope of this
article. Let's focus on sorting your data in Java.

This article describes an approach that's flexible
and can fulfill almost any need. The Strategy design
pattern will help us to make it even more powerful and convenient.
All we need is
Java 2 Platform,
Standard Edition version 1.4.2
. This code is
that simple!

What Will We Sort?

We will sort Arrays of POJOs. But it goes without
saying that you can sort Lists, too. The
java.util.Arrays class contains a number of static
methods for sorting arrays, just as
java.util.Collections has sort() methods
for Lists, so you shouldn't really worry about getting
stuck with only one of them.

In this article we will provide two very similar sorting
mechanisms, each slightly different. In the first
implementation we will explicitly set how we want to sort
our array of POJOs, and in the second implementation we will
add behavior to our POJOs to indicate how they should be
sorted. You get to decide which one to use, and this will
depend very much on your application's needs and requirements.

Before we start, let's see what our simple POJO will look like.
The Duck class is illustrated in Figure 1.

Figure 1
Figure 1. Duck POJO

As you can see, Ducks from our courtyard have only
name, size, and weight. Here is the code for this POJO:

[prettify]public class Duck {
    private String duckName;
    private int duckWeight;
    private int duckSize;
    public Duck(String s, int i, int x) {
        this.duckName = s;
        this.duckWeight = i;
        this.duckSize = x;
    }
    public String toString() {
        return("Duck with name '" + this.duckName +
                "' has weight " + this.duckWeight + 
                " and size " + this.duckSize + ".");
    }
    public String getDuckName() {
        return this.duckName;
    }
    public void setDuckName(String s) {
        this.duckName = s;
    }
    public int getDuckWeight() {
        return this.duckWeight;
    }
    public void setDuckWeight(int i) {
        this.duckWeight = i;
    }
    public int getDuckSize() {
        return this.duckSize;
    }
    public void setDuckSize(int i) {
        this.duckSize = i;
    }
}
[/prettify]

I doubt that any comments on this code are needed.

First Implementation

As mentioned above, java.util.Arrays has a few
static methods to sort arrays, one of which is
Arrays.sort(Object[] a, Comparator c). This method
sorts the specified array of objects according to the order
indicated by the specified comparator. All elements in the array
must be mutually comparable by the specified comparator. The
Comparator object has to implement the
java.util.Comparator interface and its method
compare(Object o1, Object o2). This method returns -1
(if o1 is less than o2), 0 (if
o1 and o2 are equal), or 1 (if
o1 is greater than o2). This way we
define our own rules for sorting the list of objects.

You've probably figured out that to sort on each field of the
POJO, we will need to create our own comparator implementations. Here
is an example of one, for sorting by size:

[prettify]import java.util.Comparator;
public class SortBySize implements Comparator {
    public int compare(Object f, Object s) {
        Duck o1 = (Duck) f;
        Duck o2 = (Duck) s;
        if (o1.getDuckSize() < o2.getDuckSize())
            return -1;
        if (o1.getDuckSize() == o2.getDuckSize())
            return 0;
        return 1;
    }
}
[/prettify]

Using the comparator is simple. Here is a test:

[prettify]   ...
        Duck d1 = new Duck ("Ducky", 50, 33);
        Duck d2 = new Duck ("Greenie", 44, 24);
        Duck d3 = new Duck ("Tutsie", 1, 105);
        Duck d4 = new Duck ("Lisie", 911, 87);
        Duck[] ducks = { d1, d2, d3, d4 };
    ...
        Arrays.sort(ducks, new SortBySize());
        for (int i = 0; i < ducks.length; i++) {
            System.out.println(ducks[i]);
        }
    ...
[/prettify]

To test this, unzip the
source code for this article,
change the directory to example1, and compile the test
class with:

[prettify]javac -classpath . TestDrive.java
[/prettify]

You then run the code with:

[prettify]java TestDrive
[/prettify]

You will see the output shown in Figure 2:

Figure 2
Figure 2. A "test drive" of the first sorting implementation; click the image for a full-sized screen shot.

That's all we need!

But that's not the end of the article. We may encounter sorting situations in which we don't know how to sort the
array, and our array needs to know that. This is where our
second implementation comes into play.

Second Implementation

For our second implementation we will take advantage of the java.lang.Comparable
interface. It defines the method compareTo(Object o),
which compares the Comparable object with the
specified object for ordering. It should return a negative integer,
zero, or a positive integer as this object is less than, equal to,
or greater than the specified object, as does
java.util.Comparator's compare().
Classes in core Java that have a "natural ordering" implement
Comparable, like the numeric wrapper classes
(Integer, Float, Double), String, and a few others.

To use this interface we will have to modify our POJO a bit:

[prettify]public class Duck implements Comparable {
    ...
    public int compareTo(Object ob) {
        DuckSortable o2 = (DuckSortable) ob;
        if (this.getDuckSize() < o2.getDuckSize()) return -1;
        if (this.getDuckSize() == o2.getDuckSize()) return 0;
        return 1;
    }
    ...
}
[/prettify]

As you can see, our compareTo(Object o)
implementation is based on the duck's size. Now, to sort our array
of ducks, we can use the following piece of code:

[prettify]   ...
        Duck d1 = new Duck ("Ducky", 50, 33);
        Duck d2 = new Duck ("Greenie", 44, 24);
        Duck d3 = new Duck ("Tutsie", 1, 105);
        Duck d4 = new Duck ("Lisie", 911, 87);
        Duck[] ducks = { d1, d2, d3, d4 };
    ...
        Arrays.sort(ducks);
        for (int i = 0; i < ducks.length; i++) {
            System.out.println(ducks[i]);
        }
    ...
[/prettify]

Everything will be sorted by size. But wait a minute. How can we
change the sort behavior? It looks like we have created a much bigger
headache for ourselves than we started with. Don't worry—this is where the Strategy design pattern comes into
play.

Applying the Strategy Design Pattern

The Strategy design pattern basically consists of decoupling an
algorithm from its host, and encapsulating the algorithm into a
separate class. More simply put, an object and its behavior are
separated and put into two different classes. This allows you to
switch the algorithm that you are using at any time.

When you have several objects that are basically the same and
differ only in their behavior, it is a good idea to make use of
the Strategy pattern. With Strategies, all you need to do is switch
the object's strategy, and it will immediately change how it
behaves. Obviously, the Strategy pattern sounds like a solution to
our sorting problem.

In general, the Strategy pattern can be represented with the UML
diagram in Figure 3:

Figure 3
Figure 3. The Strategy design pattern; click the image for a full-sized screen shot.

Let's see how we can apply this pattern to our second
implementation, which lacks exactly this kind of flexibility. Our
algorithm is the code that we have inside the
compareTo() method. We could have many implementations
of this method: one for sorting by size, another for sorting by weight or by
name. We can have even complex sortings by multiple fields.

Each sorting implementation will be placed in a separate class, and these are
tied together by a SortStrategy interface that all of
them implement. Now, we can describe our second implementation of
POJO sorting with this UML diagram:

Figure 4
Figure 4. Applying the Strategy pattern for our second implementation; click the image for a full-sized screen shot.

You may have noticed that a new interface, called
DuckSortable, has appeared. It's not required; we can
work without it, but keeping everything in the Duck
class is a bad practice. I prefer to follow the well-known design
principle: "Program to an interface, not an implementation."

Here are code updates for our Duck class:

[prettify]public class Duck implements DuckSortable {
    ...
    private SortStrategy sortStrategy;
    ...
    public int compareTo(Object ob) {
        return this.sortStrategy.sortingAlgorithm(this, ob);
    }
    ...
    public SortStrategy getSortStrategy() {
        return this.sortStrategy;
    }
    public void setSortStrategy(SortStrategy s) {
        this.sortStrategy = s;
    }
    ...
}
[/prettify]

The class implementing the "sort by size" will look like this:

[prettify]public class SortBySize implements SortStrategy {
     public int sortingAlgorithm(Object f, Object s) {
        DuckSortable o1 = (DuckSortable) f;
        DuckSortable o2 = (DuckSortable) s;
        if (o1.getDuckSize() < o2.getDuckSize())    return -1;
        if (o1.getDuckSize() == o2.getDuckSize())    return 0;
        return 1;
    }
}
[/prettify]

That's all we need. To do the sort, you'd do the following:

[prettify]   ...
        DuckSortable d1 = new Duck ("Mupsy", 4350, 145);
        DuckSortable d2 = new Duck ("Yaska", 464, 2344);
        DuckSortable d3 = new Duck ("Alexie", 541, 1405);
        DuckSortable d4 = new Duck ("Gismo", 4586, 55);
        DuckSortable[] ducks = { d1, d2, d3, d4 };
        ...
        // here we change SortBySize strategy, this can be done anywhere!
        for (int i = 0; i < ducks.length; i++) {
            ducks[i].setSortStrategy (new SortBySize());
        }
        ...
        Arrays.sort(ducks);
        for (int i = 0; i < ducks.length; i++) {
            System.out.println(ducks[i]);
        }
    ...
[/prettify]

The code above shows only the sort-by-size implementation,
however the example code includes implementations of other
kinds of sorts along with tests for all of them. To test the whole
sample, you can unzip the source
code
, change the directory to example2, and type:

[prettify]javac -classpath . TestDrive.java
[/prettify]

and then

[prettify]java TestDrive
[/prettify]

The output will look like Figure 5.

Figure 5
Figure 5. A "test drive" of the second sorting implementation; click the image for a full-sized screen shot.

Afterword

I hope this article will be helpful in your applications,
allowing you to create your own custom sorts and easily operate
with your POJOs. I should mention that for sorting
POJOs, we also can use a third-party comparator called
BeanPropertyComparator. It is a helpful tool, but I think it's better to stay within the range of standard Java, and
use your own code.

Resources

width="1" height="1" border="0" alt=" " />
Olexiy Prohorenko is a Sun Certified Enterprise Architect whose areas of interests include Web software architecture and development of software with frequently changing requirements.