第21条:用函数对象表示策略
C语言标准库中的qsort函数要求用一个指向comparator函数的指针作为参数,它用这个函数来比较待排序的元素。比较器有两个参数,都是指向元素的指针。通过传递不同的比较器函数,可以获得不同的排列顺序,这是策略模式的一个例子。比较器函数代表一种为元素排序的策略。
java.util表中有一个Comparator接口:
public interface Comparator<T> { public int compare(T t1, T t2); }
这是一个策略接口,具体的策略类实现该接口,因为使用了泛型,所以可以用来比较不同的数据类型。
当一个具体的策略类只被使用一次时,通常使用匿名类来声明和实例化这个具体策略类:
Arrays.sort(StringArray, new Comparator<String>() { public int compare(String s1, String s2) { return s1.length() - s2.length(); } });
比较器实现根据字符串的长度来比较。
当一个具体策略是设计用力爱重复使用的时候,通常被实现为私有的静态成员类,并通过公有的静态final域被导出:
class Host { private static class StrLenCmp implements Comparator<String>, Serializable { public int compare(String s1, String s2) { return s1.length() - s2.length(); } } public static final Comparator<String> STRING_LENGTH_COMPARATOR = new StrLenCmp(); }
String类利用这种模式,通过它的CASE_INSENSITIVE_ORDER域,导出一个不区分大小写的字符串比较器。
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 8575799808933029326L; public int compare(String s1, String s2) { int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } } return n1 - n2; } /** Replaces the de-serialized object. */ private Object readResolve() { return CASE_INSENSITIVE_ORDER; } }