Recently I posted a solution to the clock angle problem.
At the end we were left with a few questions involving how to spice the
problem up a little bit. In this post we will explore these question
more. Namely, we will introduce a seconds hand along with the hour and
minute hands, and we will explore caching.
First
of all: what if the hour and minute hands ticked for every second and
we wanted second-level accuracy? What we need to do is presume that
there’s a second hand, and add the degrees changed for each second to
the hour and minute components for each second tick. We can find the math for it, and write some code like this:
// calculate all units in degrees per second
// minute hand is 6 deg/minute plus 1/10 deg/sec
double md = m*6 + s*0.1;
// hour hand goes through 30 degrees per hour
// plus 30/60=1/2 deg/min,
// plus (1/2)/60=1/120 deg/sec
double hd = h*30 + m*0.5 + s*(1d/120d);
double result = Math.abs(hd-md);
return result > 180 ? 360 - result : result;
Second of all, if the calculation was really expensive, how could we implement caching? (Hint: Not WeakHashMap) There are a couple ways to approach this.
It
helps to understand the nature of what we’re computing. Is it
time-intensive? Memory-intensive? Does it make sense to pre-compute
values? In my caching example I took two approaches: one that
pre-computes all possible values, and one that caches values as they are
calculated.
It might make sense to pre-compute
values if the set of possible values is limited and known, and the
calculations do not adversely affect the startup time of the
application. In this case, both are true. If the calculation took a lot
of time or the amount of data to store was extraordinary (say, if we had
a clock with nanosecond precision!) then this approach would obviously
not be viable.
If
pre-computing is not viable, we need a way to determine a way to store
cached values. If we are already using a caching solution elsewhere in
our application already, the choice is easy and we can just incorporate
that. One options is Spring Cache, which provides a nice abstraction over a couple implementations (see some handy posts here, and here). Additionally, you can include EHCache and use it directly.
However,
if you are not already using caching and just need a quick one-off
caching solution (on the way to a more mature solution as your needs
grow... no need to re-invent the wheel), we can try extending
LinkedHashMap as a simple cache. Check out how we can incorporate it directly into a caching layer
over the ClockAngle class. Again, this is not a full featured cache
solution, just a quick and dirty solution that may work for a focused
part of your application for the time being.
Finally,
if we have multiple classes doing the calculations and multiple caching
techniques, it becomes apparent that there is duplicate code (in the
core calculation, and in any input validation). It makes sense to
refactor out common code and use the Decorator Pattern to compose these classes together. I think the final result is beautiful, simple, and easy to test!
No comments:
Post a Comment