Getting Started
Introduction – Tutorial
Abstracting with Function Objects
Version: 5.2.1

Lab 6: Abstracting with Function Objects

Goals: The goals of this lab is to learn how to design and use function objects - Java’s way of passing functions as arguments to methods.

Getting Started

Download the files in Lab6-ImageFiles.zip. The folder contains the files:

ImageFile.java

ILoIF.java

MTLoIF.java

ConsLoIF.java

ImageFileExamples.java

Starting with partially defined classes and examples will give you the opportunity to focus on the new material and eliminate typing in what you already know. However, make sure you understand how the class is defined, what does the data represent, and how the examples were constructed.

Create a new project Lab6-FunctionObjects and import into it all of the given files. Also add tester.jar to the Java classpath.

Introduction – Tutorial

We start by designing three familiar methods that deal with lists of files: filterSmallerThan40000, filterNamesShorterThan4, countSmallerThan40000.

Look at the first two methods. They should only differ in the body of the conditional in the class ConsListImage. The two versions look like this:

if (this.first.size() < 40000)

if (this.first.name.length() < 4)

Both represent a boolean expression that depends only on the value of this.first. Think about the filter loop function in DrRacket. Its contract and header were:

;; filter: (X -> boolean) [Listof X] -> [Listof X]

;; to construct a list from all those items

;; in alox for which p holds

(define (filter p alox)...)

The argument p was a function/predicate that consumed an item from the list (for example the first) and produced a boolean value that indicated whether the item is acceptable.

Java does not allow us to use functions or methods as arguments. To get around this problem we need to go through several steps:

Define an interface that contains as its only method the header for the desired predicate: we define the interface ISelectImageFile:

// to represent a predicate for ImageFile-s

public interface ISelectImageFile{

 

  // Return true if the given ImageFile

  // should be selected

  public boolean select(ImageFile f);

}

Now any class that implements this interface will have this predicate method. Suppose our filter method consumes an object of the type ISelectImageFile as follows:

// produce a list of ImageFiles from this list

// that satisfy the given predicate

public filter(ISelectImageFile pick);

Inside the method filter our template now includes

... pick.select(ImageFile) ... -- boolean

and so, we can replace the two conditionals by

if (pick.select(this.first))

We now need to define a class that implements this interface. It needs to define the method select that consumes an instance of ImageFile and returns true if the size of the given object is less than 40000. The following class definition accomplishes this task:

/* Select image files smaller than 40000 */

public class SmallImageFile implements ISelectImageFile {

 

  /* Return true if the given ImageFile is smaller than 40000 */

  public boolean select(ImageFile f) {

    return f.height * f.width < 40000;

  }

}

In the Examples class we can now invoke the filter method on an IListImageFile with an instance of SmallImageFile as the argument:

IListImageFile mtImagelist = new MTListImageFile();

IListImageFile imagelist = .....

IListImageFile smallImagelist = ...

 

ISelectImageFile smallFiles = new SmallImageFile();

 

// test the method filter on small image files

boolean testFilter(Tester t){

  return

  t.checkExpect(mtImagelist.filter(this.smallFiles),

                this.mtImagelist) &&

  t.checkExpect(imageList.filter(this.smallFiles),

                this.smallImagelist);

}

The conditional inside the filter method:

if (pick.select(this.first))

will select the ImageFile objects for which the size is smaller than 40000.

The file Diagram.txt shows the class diagram for these classes and interfaces. It introduces a dotted line to indicate that the argument for a method is an instance of another class or interface.

Make sure you view the image using a fixed-width font.

Abstracting with Function Objects

We will now practice the use of function objects. The only purpose for defining the class SmallImageFile is to implement one method that determines whether the given ImageFile object has the desired property (a predicate method). An instance of this class can then be used as an argument to a method that deals with ImageFiles.

Finish the work at home and save it in your portfolio.

Food for thought: Think how this program would be different if we have instead worked with lists of Books, or lists of Shapes.