5

Tips and tools for refactoring

 2 years ago
source link: https://www.codesd.com/item/tips-and-tools-for-refactoring.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Tips and tools for refactoring

advertisements

I have some code that consists of a lot (several hundreds of LOC) of uggly conditionals i.e.

SomeClass someClass = null;

if("foo".equals(fooBar)) {
    // do something possibly involving more if-else statments
    // and possibly modify the someClass variable among others...
} else if("bar".equals(fooBar)) {
    // Same as above but with some slight variations
} else if("baz".equals(fooBar)) {
    // and yet again as above
}
    //... lots of more else ifs
} else  {
    // and if nothing matches it is probably an error...
    // so there is some error handling here
}

// Some code that acts on someClass
GenerateOutput(someClass);

Now I had the idea of refactoring this kind of code something along the lines of:

abstract class CheckPerform<S,T,Q> {
    private CheckPerform<T> next;
    CheckPerform(CheckPerform<T> next) {
        this.next = next;
    }

    protected abstract T perform(S arg);
    protected abstract boolean check(Q toCheck);

    public T checkPerform(S arg, Q toCheck) {
        if(check(toCheck)) {
            return perform(arg);
        } 

        // Check if this CheckPerform is the last in the chain...
        return next == null ? null : next.checkPerform();
    }
}

And for each if statment generate a subclass of CheckPerform e.g.

class CheckPerformFoo extends CheckPerform<SomeInput, SomeClass, String> {
    CheckPerformFoo(CheckPerform<SomeInput, SomeClass, String> next) {
        super(next);
    }

    protected boolean check(String toCheck) {
        // same check as in the if-statment with "foo" above"
        returs "foo".equals(toCheck);
    }

    protected SomeClass perform(SomeInput arg) {
        // Perform same actions (as in the "foo" if-statment)
        // and return a SomeClass instance (that is in the
        // same state as in the "foo" if-statment)
    }
}

I could then inject the diffrent CheckPerforms into eachother so that the same order of checks are made and the corresponding actions taken. And in the original class I would only need to inject one CheckPerform object. Is this a valid approach to this type of problem? The number of classes in my project is likely to explode, but atleast I will get more modular and testable code. Should I do this some other way?

Since these if-else-if-...-else-if-else statments are what I would call a recurring theme of the code base I would like to do this refactoring as automagically as possible. So what tools could I use to automate this?

a) Some customizable refactoring feature hidden somewhere in an IDE that I have missed (either in Eclipse or IDEA preferably) b) Some external tool that can parse Java code and give me fine grained control of transformations c) Should I hack it myself using Scala? d) Should I manually go over each class and do the refactoring using the features I am familiar with in my IDE?

Ideally the output of the refactoring should also include some basic test code template that I can run (preferably also test cases for the original code that can be run on both new and old as a kind of regression test... but that I leave for later).

Thanks for any input and suggestions!


What you have described is the Chain of Responsibility Pattern and this sounds like it could be a good choice for your refactor. There could be some downsides to this.

  • Readability Because you are going to be injecting the the order of the CheckPerformers using spring or some such, this means that it is difficult to see what the code will actually do at first clance.
  • Maintainence If someone after you wants to add a new condition, as well as adding a whole new class they also have to edit some spring config. Choosing the correct place to add there new CheckPerformer could be difficult and error prone.
  • Many Classes Depending on how many conditions you have and how much repeated code within those conditions you could end up with a lot of new classes. Even though the long list of if else its very pretty, the logic it in one place, which again aids readability.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK