4.16. Modeling Loops with Closures

Problem

You need to execute a Closure multiple times.

Solution

Use a WhileClosure, passing in a Predicate and a Closure. The WhileClosure will execute the Closure as long as a Predicate evaluates to true. The following example demonstrates a Closure named drive, which operates on a Car object and a Predicate named hasFuel, which evaluates the Car object. Each time a Car is passed to drive, a gallon of fuel is used, and hasFuel will evaluate to true if the amount of fuel in a car is greater than zero. The WhileClosure, useAllFuel, evaluates drive until hasFuel evaluates to false:

import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.functors.WhileClosure;

Closure drive = new Closure( ) {
    public void execute(Object input) {
        Car car = (Car) input;
        car.setFuel( car.getFuel( ) - 1 );
    }
}

Predicate hasFuel = new Predicate( ) {
    public boolean evaluate(Object object) {
        Car car = (Car) input;
        return car.getFuel( ) > 0;
    }
}

Closure useAllFuel = new WhileFuel( hasFuel, drive );

Car car = new Car( );
car.setMakeModel( "Ford Escort" );
car.setFuel( 20 );
System.out.println( "Car before while closure: " + car );

useAllFuel.execute( car );
System.out.println( "Car after while closure: " + car );

The WhileClosure, useAllFuel, takes a Car object, executing a Closure and evaluating a Predicate after every execution. The state of the car is printed both before and after it is passed to the WhileClosure:

Car before while closure: Ford Escort with 20 gallons of fuel.
Car after while closure: Ford Escort with no fuel.

Discussion

If you need to execute a Closure a set number of times, you can also use a ForClosure, passing in an int that specifies the number of times an object is passed to the execute( ) method of a Closure. This example uses the same Closure defined in the Solution, but, this time, the drive Closure is only executed five times:

               Closure driveSome = new ForClosure( 5, drive );

Car car = new Car( );
car.setMakeModel( "Toyota Camry" );
car.setFuel( 20 );

System.out.println( "Car before for closure: " + car );

driveSome.execute( car );

System.out.println( "Car after for closure: " + car );

Since the driveSome Closure is called only five times, the Camry still has 15 gallons after the ForClosure is executed:

Car before for closure: Toyota Camry with 20 gallons of fuel.
Car after for closure: Toyota Camry with 15 gallons of fuel.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.27.72