One implementation for each field is not so bad, however there is a lot of duplication in your code. You must have one comparator per field. If you want to compare based on several fields, but in a different order, wrap atomic comparators (Decorator pattern):
public abstract class AbstractComparator implements Comparator<User> { private final AbstractComparator next; public AbstractComparator(AbstractComparator next) { this.next = next; } public int compare(User user1, User user2) { int result = doCompare(user1, user2); if (result != 0) { return result; } else { return next != null? next.compare(user1, user2) : 0; } } public abstract int doCompare(User user1, User user2); }
class ById extends AbstractComparator { public ById(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return (int) (user1.getId() - user2.getId()); } }
class ByName extends AbstractComparator { public ByName(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return user1.getName().compareTo(user2.getName()); } }
class ByAge extends AbstractComparator { public ByAge(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return user1.getAge() - user2.getAge(); } }
And use:
Comparator<User> comp1 = new ById(new ByName(new ByAge(null))); Comparator<User> comp2 = new ByAge(new ByName(new ById(null)));
comp1 first sorts by id , and if it is equal, returns in name and age as a last resort. The API is pretty straightforward.
For convenience, you should put all By* classes as static inner classes of User : User.ByName , User.ByAge , etc. or perhaps with some factory methods: User.byName(User.byAge(null)) . With some static import you can enjoy the pleasant:
Collections.sort(users, byName(byAge(byId(null))));
Alternatively, you can see CompareToBuilder from Commons Lang.