Have a system of comparators, backed by generics. Every comparer will also know what is next in line. For example:
interface IComparer<T> {
boolean areDifferent (T first, T second);
}
class FontComparer implements IComparer<Font> {
@Override
public boolean areDifferent(Font first, Font second) {
// Compare fonts start
// ..
// Compare fonts end
return new BorderComparer().areDifferent(first.getBorder(), second.getBorder());
}
}
class BorderComparer implements IComparer<Border> {
@Override
public boolean areDifferent(Border first, Border second) {
//Do border comparison alone
return false;
}
}
You could setup a comparer chain now, and bail out when comparison fails. Otherwise, comparison goes to the comparer next in the chain.
The client code will finally look like:
Object one = new Object();
Object two = new Object();
new ObjectComparer().areDifferent(one, two);