4

I need to compare two Objects. If there is a difference I need to log it corresponding to particular difference and return the true.

For example:

private boolean compTwoObjects(Object objA, Object ObjB) {
   if(objA.getType() != objB.getType()) {
      logTheDifference("getType is differing");
      return true;
   }
                   .
                   .
                   .
   // Now this could invoke other composite methods
   if(checkFont(objA.getFont(), objB.getFont()) {
      logTheDifference("Font is differing");
      return true;
   }
}


private boolean checkFont(Font fontObjA, Font fontObjB) {
   if(fontObjA.getBold() != fontObjB.getBold()) {
      logTheDifference("font bold formatting differs");
      return true;
   }
                   .
                   .
                   .
   if(fontObjA.getAllCaps() != fontObjB.getAllCaps()) {
      logTheDifference("font all caps formatting differs");
      return true;
   }
                   .
                   .
                   .
   if(checkBorderDiff(fontObjA.getBorder(), fontObjB.getBorder())) {
      logTheDifference("border diff");
      return true;
   }
}

private boolean checkBorderDiff(Border borderObjA, Border borderObjB) {
    if (borderObjA.getColor() != null || borderObjB.getColor() != null) {
       if (!borderObjA.getColor().equals(borderObjB.getColor())) {
            logIt("border color differing");
            return true;
        }
    }

    if (borderObjA.getDistanceFromText() != borderObjB.getDistanceFromText()) {
        logIt("distance of the border from text or from the page edge in points differing");
        return true;
    }

    if (borderObjA.isVisible() != borderObjB.isVisible()) {
        logIt("border visibility differing");
        return true;
    }

    if (borderObjA.getLineStyle() != borderObjB.getLineStyle()) {
        logIt("line style differing for border");
        return true;
    }

    if (borderObjA.getLineWidth() != borderObjB.getLineWidth()) {
        logIt("border width in points differing");
        return true;
    }

    if (borderObjA.getShadow() != borderObjB.getShadow()) {
        logIt("border shadow differing");
        return true;
    }
}

//And it is going like this.

My problem is I want to avoid multiple if statements in the methods. Also I want to log the messages corresponding to particular difference.

I have read few similar type of problems on stackoverflow solved either by command pattern or HashMap. But they don't include comparisons in that.

I want to refactor my code to get rid of series of if's.

unknown_boundaries
  • 1,482
  • 3
  • 25
  • 47
  • 1
    Have a look at this question http://stackoverflow.com/questions/437093/javabeans-comparison – nhu Dec 26 '13 at 10:25

4 Answers4

4

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);
aquaraga
  • 4,138
  • 23
  • 29
  • here how can we log specifically? – unknown_boundaries Dec 26 '13 at 14:02
  • @PrakharBansal Log it in the appropriate 'areDifferent' methods. For eg; logTheDifference("font bold formatting differs"); will be done in the FontComparer's areDifferent method. – aquaraga Dec 30 '13 at 08:46
  • But the thing is in this way the problem of series of if's is not solved as the FontComparer class will need to have all the ifs for the comparison of methods such as: getBold(), getAllCaps() etc. – unknown_boundaries Dec 30 '13 at 08:57
  • I'm not entirely sure why you would again want to split up the comparisons within the FontComparer, unless it is a **really** long list of if comparisons within the FontComparer. In such a case, you could adopt a hybrid approach - use Comparers for high level splitting; and within each comparer, use the enum solution given by @OldCurmudgeon. However, I must say that such a fine-grained decomposition could adversely affect the readability of your program. – aquaraga Dec 31 '13 at 04:32
  • yes long list of comparisons in each of the comparer. Yup because of readability and maintainability I'm afraid. Thanks. – unknown_boundaries Dec 31 '13 at 05:27
2

Have you considered enums?

private enum FontCmp {

    Bold {
                @Override
                boolean cmp(Font a, Font b) {
                    return a.getBold() != b.getBold();
                }
            },
    AllCaps {
                @Override
                boolean cmp(Font a, Font b) {
                    return a.getAllCaps() != b.getAllCaps();
                }
            },
    Border {
                @Override
                boolean cmp(Font a, Font b) {
                    return BorderCmp.compare(a.getBorder(), b.getBorder());
                }
            };

    // Each enum has one of these.
    abstract boolean cmp(Font a, Font b);

    // Compare them all and log any failures.
    static boolean compare(Font a, Font b) {
        for (FontCmp c : FontCmp.values()) {
            if (c.cmp(a, b)) {
                logIt("FontCmp-" + c + " failed");
                return false;
            }
        }
        return true;
    }
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • No I have not considered the enum approach, thanks it seems very good. Any way not to write overridden method boolean cmp(Font a, Font b) in each enum value. – unknown_boundaries Dec 26 '13 at 14:23
  • @PrakharBansal - You will have to define how to compare two `Font.Bold`s somewhere, however you write it - unless of course you go down the reflection route, in which case you then have two problems, as the saying goes. – OldCurmudgeon Dec 26 '13 at 16:42
1

You could also use reflection as described here. Also look into introspection as described here

Edgesoft
  • 282
  • 2
  • 16
0

Fundamentally you are trying to do a series of comparisons, so there is little choice but to do a series of comparisons.

What you could do is define an interface/enum/abstract class which is a FieldChecker. That FieldChecker would have an abstract method implemented differently in each FieldChecker:

 String performCheck(Font a, Font b) {
     if (DO CHECK HERE) {
         return "failure message";
     }
     return null;
 }

Then your check function just becomes:

for (FieldChecker fc: fieldCheckers) {
    String res = fc.performCheck(a,b);
    if (res != null) {
       return res;
    }
}
return "All ok";
Tim B
  • 40,716
  • 16
  • 83
  • 128