Template method with return value

593 views Asked by At

I have an outline for an algorithm - some logical steps that has to be performed in a specific order. The result of the algorithm has to be some number. Naturally this led me to the idea of using the template method pattern. This works fine for void methods but here comes my problem: each of the steps in the algorithm is not a void method but is allowed to return a number (so they are int methods) - if a step returns a non-zero number, this number is the result of the algorithm's execution, if it is a zero - the execution continues with the next step.

This might sound really trivial but I just still find it somehow ugly to have something like:

public int algorithm() {
    int resultStep1 = step1();
    if (resultStep1!=0) {
        return resultStep1;
    }
    int resultStep2 = step2();
    if (resultStep2!=0) {
        return resultStep2;
    }
    ...
}

Of course step1(), step2() and so on are abstract methods and have their own specific implementations in the corresponding classes that extend mine.

The other idea that came to my mind was using exceptions but as we are talking about control flow here this would be an anti-pattern.

Am I missing something here or is this just the way I have to write it?

2

There are 2 answers

8
AudioBubble On

You can do the following:

if(setResultAndCheckIsNonZero(step1())) {
    return result;
} else if(setResultAndCheckIsNonZero(step2())) {
    return result;
} else if ...

Where:

private int result;

private boolean setResultAndCheckIsNonZero(int x) {
    result = x;
    if(result != 0) 
        return true;
    return false;
}
6
weston On

Java 7

You can define an interface for your steps:

interface Step {
    int step();
}

Then use a list of steps:

ArrayList<Step> steps = new ArrayList<Step>();

Iterate over it like so:

public int algorithm() {
    for (Step step : steps) {
        int result = step.step();
        if (result != 0)
            return result;
    }
    return 0;
}

To initialise that list, you can do this using anonymous implementation classes:

steps.add(new Step() {
    @Override
    public int step() {
        return step1(); //or the code directly
    }
});

steps.add(new Step() {
    @Override
    public int step() {
        return step2();
    }
});

Or create well named implementation classes for each step:

public class Step1 implements Step {
    @Override
    public int step() {
        // TODO Auto-generated method stub
        return 0;
    }       
}

And add to list like this:

steps.add(new Step1());
steps.add(new Step2());

Using lambda in Java8

No interface required.

List:

ArrayList<Supplier<Integer>> steps = new ArrayList<Supplier<Integer>>();

Setup:

steps.add(()-> step1());
steps.add(()-> step2());

Algorithm:

public int algorithm() {
    for (Supplier<Integer> step : steps) {
        int result = step.get();
        if (result != 0)
            return result;
    }
    return 0;
}