Java Design Issue: Enforce method call sequence
There is a question which was recently asked to me in an interview.
Problem: There is a class meant to profile the execution time of the code. The class is like:
Class StopWatch {
long startTime;
long stopTime;
void start() {// set startTime}
void stop() { // set stopTime}
long getTime() {// return difference}
}
The client is expected to create an instance of the StopWatch and call methods accordingly. User code can mess up the use of the methods leading to unexpected results. Ex, start(), stop() and getTime() calls should be in order.
This class has to be "reconfigured" so that user can be prevented from messing up the sequence.
I proposed use of custom exception if stop() is called before start(), or doing some if/else checks, but interviewer was not satisfied.
Is there a design pattern to handle these kind of situations?
Edit: The class members and method implementations can be modified.
Solution 1:
First there is the fact that implementing an own Java profiler is a waste of time, since good ones are available (maybe that was the intention behind the question).
If you want to enforce the correct method order at compile time, you have to return something with each method in the chain:
-
start()
has to return aWatchStopper
with the stop method. - Then
WatchStopper.stop()
has to return aWatchResult
with thegetResult()
method.
External Construction of those helper classes as well as other ways of accessing their methods have to be prevented of course.
Solution 2:
With minor changes to the interface, you can make the method sequence the only one that can be called - even at compile time!
public class Stopwatch {
public static RunningStopwatch createRunning() {
return new RunningStopwatch();
}
}
public class RunningStopwatch {
private final long startTime;
RunningStopwatch() {
startTime = System.nanoTime();
}
public FinishedStopwatch stop() {
return new FinishedStopwatch(startTime);
}
}
public class FinishedStopwatch {
private final long elapsedTime;
FinishedStopwatch(long startTime) {
elapsedTime = System.nanoTime() - startTime;
}
public long getElapsedNanos() {
return elapsedTime;
}
}
The usage is straightforward - every method returns a different class which only has the currently applicable methods. Basically, the state of the stopwatch is encapsuled in the type system.
In comments, it was pointed out that even with the above design, you can call stop()
twice. While I consider that to be added value, it is theoretically possible to screw oneself over. Then, the only way I can think of would be something like this:
class Stopwatch {
public static Stopwatch createRunning() {
return new Stopwatch();
}
private final long startTime;
private Stopwatch() {
startTime = System.nanoTime();
}
public long getElapsedNanos() {
return System.nanoTime() - startTime;
}
}
That differs from the assignment by omitting the stop()
method, but that's potentially good design, too. All would then depend on the precise requirements...
Solution 3:
We commonly use StopWatch from Apache Commons StopWatch check the pattern how they've provided.
IllegalStateException is thrown when the stop watch state is wrong.
public void stop()
Stop the stopwatch.
This method ends a new timing session, allowing the time to be retrieved.
Throws:
IllegalStateException - if the StopWatch is not running.
Straight forward.