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
In hindsight it sounds like they were looking for the execute around pattern. They're usually used to do things like enforce closing of streams. This is also more relevant due to this line:
Is there a design pattern to handle these kind of situations?
The idea is you give the thing that does the "executing around" some class to do somethings with. You'll probably use Runnable
but it's not necessary. (Runnable
makes the most sense and you'll see why soon.) In your StopWatch
class add some method like this
public long measureAction(Runnable r) {
start();
r.run();
stop();
return getTime();
}
You would then call it like this
StopWatch stopWatch = new StopWatch();
Runnable r = new Runnable() {
@Override
public void run() {
// Put some tasks here you want to measure.
}
};
long time = stopWatch.measureAction(r);
This makes it fool proof. You don't have to worry about handling stop before start or people forgetting to call one and not the other, etc. The reason Runnable
is nice is because
Runnable
to be done.(If you were using it to enforce stream closing then you could put the actions that need to be done with a database connection inside so the end user doesn't need to worry about how to open and close it and you simultaneously force them to close it properly.)
If you wanted, you could make some StopWatchWrapper
instead leave StopWatch
unmodified. You could also make measureAction(Runnable)
not return a time and make getTime()
public instead.
The Java 8 way to calling it is even simpler
StopWatch stopWatch = new StopWatch();
long time = stopWatch.measureAction(() - > {/* Measure stuff here */});
A third (hopefully final) thought: it seems what the interviewer was looking for and what is being upvoted the most is throwing exceptions based on state (e.g., if
stop()
is called beforestart()
orstart()
afterstop()
). This is a fine practice and in fact, depending on the methods inStopWatch
having a visibility other than private/protected, it's probably better to have than not have. My one issue with this is that throwing exceptions alone will not enforce a method call sequence.For example, consider this:
class StopWatch { boolean started = false; boolean stopped = false; // ... public void start() { if (started) { throw new IllegalStateException("Already started!"); } started = true; // ... } public void stop() { if (!started) { throw new IllegalStateException("Not yet started!"); } if (stopped) { throw new IllegalStateException("Already stopped!"); } stopped = true; // ... } public long getTime() { if (!started) { throw new IllegalStateException("Not yet started!"); } if (!stopped) { throw new IllegalStateException("Not yet stopped!"); } stopped = true; // ... } }
Just because it's throwing
IllegalStateException
doesn't mean that the proper sequence is enforced, it just means improper sequences are denied (and I think we can all agree exceptions are annoying, luckily this is not a checked exception).The only way I know to truly enforce that the methods are called correctly is to do it yourself with the execute around pattern or the other suggestions that do things like return
RunningStopWatch
andStoppedStopWatch
that I presume have only one method, but this seems overly complex (and OP mentioned that the interface couldn't be changed, admittedly the non-wrapper suggestion I made does this though). So to the best of my knowledge there's no way to enforce the proper order without modifying the interface or adding more classes.I guess it really depends on what people define "enforce a method call sequence" to mean. If only the exceptions are thrown then the below compiles
StopWatch stopWatch = new StopWatch(); stopWatch.getTime(); stopWatch.stop(); stopWatch.start();
True it won't run, but it just seems so much simpler to hand in a
Runnable
and make those methods private, let the other one relax and handle the pesky details yourself. Then there's no guess work. With this class it's obvious the order, but if there were more methods or the names weren't so obvious it can begin to be a headache.
More hindsight edit: OP mentions in a comment,
"The three methods should remain intact and are only interface to the programmer. The class members and method implementation can change."
So the below is wrong because it removes something from the interface. (Technically, you could implement it as an empty method but that seems to be like a dumb thing to do and too confusing.) I kind of like this answer if the restriction wasn't there and it does seem to be another "fool proof" way to do it so I will leave it.
To me something like this seems to be good.
class StopWatch {
private final long startTime;
public StopWatch() {
startTime = ...
}
public long stop() {
currentTime = ...
return currentTime - startTime;
}
}
The reason I believe this to be good is the recording is during object creation so it can't be forgotten or done out of order (can't call stop()
method if it doesn't exist).
One flaw is probably the naming of stop()
. At first I thought maybe lap()
but that usually implies a restarting or some sort (or at least recording since last lap/start). Perhaps read()
would be better? This mimics the action of looking at the time on a stop watch. I chose stop()
to keep it similar to the original class.
The only thing I'm not 100% sure about is how to get the time. To be honest that seems to be a more minor detail. As long as both ...
in the above code obtain current time the same way it should be fine.