In addition to the earlier answers note that there are more possibilities. First is to separate the template method into its own class:
public interface Flow {
void phase1();
void phase2();
}
public final class FlowManager {
private final Flow flow;
public FlowManager(Flow flow) {
this.flow = flow;
}
public void startFlow() {
flow.phase1();
flow.phase2();
}
}
If you are already using FlowManager.phaseX
methods you may make it implementing the Flow
interface as well:
public final class FlowManager implements Flow {
private final Flow flow;
public FlowManager(Flow flow) {
this.flow = flow;
}
public void startFlow() {
flow.phase1();
flow.phase2();
}
@Override
public void phase1() {
flow.phase1();
}
@Override
public void phase2() {
flow.phase2();
}
}
This way you explicitly signal that users have to implement the Flow
interface, but they cannot change the startFlow
template method as it's declared in final class.
Java 8 adds a new functional pattern to solve your problem:
public final class FlowManager {
private final Runnable phase1;
private final Runnable phase2;
public FlowManager(Runnable phase1, Runnable phase2) {
this.phase1 = phase1;
this.phase2 = phase2;
}
public void startFlow() {
phase1.run();
phase2.run();
}
public void phase1() {
phase1.run();
}
public void phase2() {
phase2.run();
}
}
Well, this code works even prior to Java 8, but now you can create the FlowManager
using lambdas or method references which is much more convenient.
You can also combine the approaches: define the interface and provide a way to construct it from lambdas:
public interface Flow {
void phase1();
void phase2();
static Flow of(Runnable phase1, Runnable phase2) {
return new Flow() {
@Override
public void phase1() {
phase1.run();
}
@Override
public void phase2() {
phase2.run();
}
};
}
}
The Collector
interface in Java 8 is implemented in similar way. Now depending on the users preference they can either implement the interface directly or use Flow.of(...)
and pass the lambdas or method references there.