You need to evaluate an object to see if it meets criteria, and you want to
capture these criteria in a custom Predicate
.
Implement the Predicate
interface and capture your logic in an evaluate( )
method. Example 4-5
is a simple Predicate
implementation
that always returns true
; it is
intended as a basic example of how to implement the Predicate
interface.
Example 4-5. A simple Predicate implementation
import org.apache.commons.collections.Predicate; public class SimplePredicate implements Predicate { public boolean evaluate(Object object) { // do something. boolean result = true; return result; } }
Predicates
can be used in any
number of situations, such as validating user input, filtering a
Collection
, or just as a replacement
for complex conditional logic. A Predicate
can be as simple or as complex as
you need it to be; the only contract it must satisfy is the production
of a boolean
result from an evaluate( )
method.
To demonstrate the process of writing a fairly complex
implementation of the Predicate
interface, a contrived example is developed in Example 4-6. Your application evaluates
the condition of the space shuttle and makes a determination for
launch—go or no go. Some of the criteria include the temperature of the
launch pad, the status of the crew, and the presence (or absence) of
fuel. In the end, your boss is looking for thumbs up or thumbs down, and
you decide to write a program that returns a boolean
decision. This decision is implemented
in the LaunchPredicate
class.
Example 4-6. Implementing the Predicate interface
package com.discursive.jccook.collections.predicate; import org.apache.commons.collections.Predicate; public class LaunchPredicate implements Predicate { public LaunchPredicate( ) {} public boolean evaluate(Object object) { boolean launchGo = false; LaunchStats stats = (LaunchStats) object; boolean crewReady = stats.isCrewPresent( ) && stats.isCrewHealthy( ); boolean fueled = stats.isShuttleFueled( ) && stats. isFuelIgnitionReady( ); boolean withinLaunchWindow = stats.isLaunchWindowOpen( ); boolean properWeather = ( stats.temperature( ) > 35 ) && ( !stats.isLightningDangerPresent( ) ); // Check the crew, fuel, and launch time if( crewReady && fueled && withinLaunchWindow ) { launchGo = true; } // Override a GO decision if the weather is bad if( !properWeather ) { launchGo = false; } return launchGo; } }
A shuttle launch is predicated on the presence and health of the
crew, the state of the fuel, and the time of the launch event. A final
weather check is performed to ensure that the temperature of the shuttle
is not below 35 degrees Fahrenheit. If this critical temperature limit
is not met, the Predicate
overrides
the previous decision to launch. Using a LaunchPredicate
encapsulates your decision
logic in one object, making it easier to upgrade, maintain, and test
this decision process. Your unit tests can pass a mock object to this
predicate, testing every possible permutation of possible inputs. The
following example demonstrates the use of the LaunchPredicate
:
LaunchPredicate launchDecision = new LaunchPredicate( ); LaunchStats stats = measureLaunchStatistics( ); if( launchDecision.evaluate( stats ) ) { System.out.println( "We are Go for Ignition." ); } else { System.out.println( "Abort mission." ); }
The real Space Shuttle Launch Team has the outrageously complex
job of monitoring and controlling every aspect of launching a
spacecraft, and I'm sure that NASA doesn't implement the Predicate
interface from Commons Collections.
While it isn't related to the topic of open source Java programming, it
is a fascinatingly complex piece of software that maintains a shuttle
launch. It is written in something called high-order assembly
language/shuttle (HAL/S). If you are interested in learning more about
one of the most complex pieces of software, take a look at NASA's Space
Shuttle Launch Team website at http://science.ksc.nasa.gov/shuttle/countdown/launch-team.html.
(Besides, I'm sure you are amused that NASA controls spacecraft with an
assembly language known as HAL.)
This recipe mentions the use of a mock object to test a Predicate
. One of the attractions of using a
Predicate
to encapsulate any complex
condition is the ability to write a test for this condition logic;
mock objects
are a method of unit
testing that involves passing a mock implementation of an object to a
class i
n a
test. For more information about mock objects, see http://www.mockobjects.com/.