G'day comrades. I have a problem.
I have two methods which are completely duplicate apart from that they are accessing a different field. I cannot pass the field value as a parameter because accessing takes place inside a loop (simplified example):
public final class Thing {
ImmutableList<Box> boxes;
public int getNumberOfApples() {
int total = 0;
for (Box box : boxes) {
total += box.getApplesCount();
}
return total;
}
public int getNumberOfPears() {
int total = 0;
for (Box box : boxes) {
total += box.getPearsCount();
}
return total;
}
}
I could put my fruit into a map and passed the field name as a parameter but it looks dirty and I am quite happy with the current class composition. So the question is - how do I refactor my code to have a single method of type:
public int getNumberOfFruit(SomethingMagic) {
moreMagic;
return total;
}
Cheerio.
Well, you could have something like:
public interface Function<In, Out> {
Out apply(In input);
}
Then:
public int getCount(Function<Box, Integer> projection) {
int total = 0;
for (Box box : boxes) {
total += projection(box);
}
return total;
}
For the moment constructing that projection will be ugly, e.g.
int pears = thing.getCount(new Function<Box, Integer>() {
@Override public Integer apply(Box input) {
return box.getPearsCount();
}
});
but in Java 8, it'll be much simpler with lambda expressions:
int pears = thing.getCount(box -> box.getPearsCount());
Note that Raffaele Rossi's answer is slightly more specific than mine by making the interface non-generic. This means it can be more efficient, as there's no need to box the counts - but less reusable, of course. Which approach you decide to use is a judgement call which will largely depend on your actual use case.
See more on this question at Stackoverflow