Java Reference
In-Depth Information
But this would mean that every time we wanted to add in a new set of time points to the plot,
we would have to modify the
MetricDataGraph
class. We can resolve this issue by introdu-
cing an abstraction, which I'll call a
TimeSeries
, that represents a series of points in time.
Now our
MetricDataGraph
API can be simplified to not depend upon the different types of
metric that it needs to display, as shown in
Example 8-39
.
Example 8-39. Simplified MetricDataGraph API
class
class
MetricDataGraph
MetricDataGraph
{
public
public
void
void
addTimeSeries
(
TimeSeries values
);
}
Each set of metric data can then implement the
TimeSeries
interface and be plugged in. For
example, we might have concrete classes called
UserTimeSeries
,
SystemTimeSeries
, and
IoTimeSeries
. If we wanted to add, say, the amount of CPU time that gets stolen from a
machine if it's virtualized, then we would add a new implementation of
TimeSeries
called
StealTimeSeries
.
MetricDataGraph
has been extended but hasn't been modified.
Higher-order functions also exhibit the same property of being open for extension, despite
being closed for modification. A good example of this is the
ThreadLocal
class that we en-
countered earlier. The
ThreadLocal
class provides a variable that is special in the sense that
each thread has a single copy for it to interact with. Its static
withInitial
method is a
higher-order function that takes a lambda expression that represents a factory for producing
an initial value.
This implements the open/closed principle because we can get new behavior out of
ThreadLocal
without modifying it. We pass in a different factory method to
withInitial
and get an instance of
ThreadLocal
with different behavior. For example, we can use
ThreadLocal
to produce a
DateFormatter
that is thread-safe with the code in
Example 8-40. A ThreadLocal date formatter
// One implementation
ThreadLocal
<
DateFormat
>
localFormatter
=
ThreadLocal
.
withInitial
(() ->
new
new
SimpleDateFormat
());
// Usage
DateFormat formatter
=
localFormatter
.
get
();