Function pointers were omitted from the Java programming language because object references can be used to provide the same functionality. Invoking a method on an object typically performs some operation on that object. However, it is possible to define an object whose methods perform operations on other objects, passed explicitly to the methods.
An instance of a class that exports exactly one such method is effectively a pointer to that method. Such instances are known as function objects. For example, consider the following class:
This class exports a single method that takes two strings and returns a negative integer if the first string is shorter than the second, zero if the two strings are of equal length, and a positive integer if the first string is longer. This method is a comparator that orders strings based on their length instead of the more typical lexicographic ordering. A reference to a StringLengthComparator object serves as a “function pointer” to this comparator,
allowing it to be invoked on arbitrary pairs of strings. In other words, a StringLengthComparator instance is a concrete strategy for string comparison.
As is typical for concrete strategy classes, the StringLengthComparator class is stateless: It has no fields, hence all instances of the class are functionally equivalent to one another. Thus it could just as well be a singleton to save on unnecessary object creation costs :
To pass a StringLengthComparator instance to a method, we need an appropriate type for the parameter. It would do no good to use StringLengthComparator because clients would be unable to pass any other comparison strategy. Instead, we need to define a Comparator interface and modify StringLengthComparator to implement this interface. In other words, we need to define a strategy interface to go with the concrete strategy class. Here it is:
An instance of a class that exports exactly one such method is effectively a pointer to that method. Such instances are known as function objects. For example, consider the following class:
class StringLengthComparator { public int compare(String s1, String s2) { return s1.length() - s2.length(); } }
This class exports a single method that takes two strings and returns a negative integer if the first string is shorter than the second, zero if the two strings are of equal length, and a positive integer if the first string is longer. This method is a comparator that orders strings based on their length instead of the more typical lexicographic ordering. A reference to a StringLengthComparator object serves as a “function pointer” to this comparator,
allowing it to be invoked on arbitrary pairs of strings. In other words, a StringLengthComparator instance is a concrete strategy for string comparison.
As is typical for concrete strategy classes, the StringLengthComparator class is stateless: It has no fields, hence all instances of the class are functionally equivalent to one another. Thus it could just as well be a singleton to save on unnecessary object creation costs :
class StringLengthComparator { private StringLengthComparator() { } public static final StringLengthComparator INSTANCE = new StringLengthComparator(); public int compare(String s1, String s2) { return s1.length() - s2.length(); } }
To pass a StringLengthComparator instance to a method, we need an appropriate type for the parameter. It would do no good to use StringLengthComparator because clients would be unable to pass any other comparison strategy. Instead, we need to define a Comparator interface and modify StringLengthComparator to implement this interface. In other words, we need to define a strategy interface to go with the concrete strategy class. Here it is:
// Strategy interface public interface Comparator { public int compare(Object o1, Object o2); }
No comments:
Post a Comment