第5章 替换C中的结构(Replace structures with classes)
19 使用类替换C中的结构体
只包含数据域(data field)的退化的Java类基本上等同于C中的结构体。
公有的类不应该把其内部的数据域暴露出来,而是应该进行封装。
如果一个类是包私有的或是一个私有的嵌套类,直接暴露其数据域并没有什么问题。
20 使用类继承结构替换联合体(Replace unions with class hierarchies)
C中的联合体一般由两个部分组成:一个是联合结构,一个是一个标签域。标签域用来表明联合结构中存放的是什么类型的数据。该标签通常是一个枚举类型。这样的联合体通常称为有区别的联合体(discriminated union)。
为了将一个有区别的联合体转换成一个类继承结构,首先要定义一个抽象类,该类中对于每一个依赖于联合体标签域的操作都有一个对应的抽象方法。如果存在不依赖于标签域的操作,则把这些操作变为根类(上述抽象类)中的具体方法。然后对每一个可以由该有区别的联合体表示的类型,定义一个根类的具体子类。
类继承结构的优越性:
1) 类继承结构提供了类型安全性。
2) 代码简单和清晰。
3) 容易扩展,即使是多个团体独立工作。
4) 可以反映类型之间自然的继承关系,从而提供更好的灵活性和编译时刻类型检查。
21 使用类替换枚举结构(Replace enum constructs with classes)
Java提供的类型安全枚举模式(typesafe enum pattern)可以很好的解决C中枚举类型的种种问题。基本的思路很简单:定义一个类表示枚举成员,不提供任何公共的构造函数,而是为枚举类型中的每个常量提供一个public static final fields。
举例如下:
public class Suit {
private final String name;
private Suit(String name) {this.name = name;}
public String toString() {return name;}
public static final Suit CLUBS = new Suit(“Clubs”);
public static final Suit DIAMONDS = new Suit(“Diamonds”);
public static final Suit HEARTS = new Suit(“Hearts”);
public static final Suit SPADES = new Suit(“Spades”);
}
当类型安全枚举类需要实现Comparable接口时,需要使用一个静态变量,nextOrdinal来对每一个实例赋予一个序数值。这些序数值被compareTo方法用来比较各个实例。
private static int nextOrdinal = 0;
private final int ordinal = nextOrdinal++;
当使用序数值的类型安全枚举类需要序列化时,需要提供readResolve方法:
private Object readResolve() throws ObjectStreamException {
return PRIVATE_VALUES[ordinal];
}
如果类型安全枚举类中有的方法的行为因类常量的不同而不同,则应该使用一个私有类或是匿名内部类来实现该行为。
使用类型安全枚举类的客户可以使用==而不是equals方法。
如果一个类型安全枚举类被广泛使用,它应该是一个顶层类;如果它被绑定到一个特定的顶层类,则它应该是该顶层类的静态成员类。
为了是一个类型安全枚举类可扩展,只需要提供保护的构造函数即可。
可扩展的类型安全枚举类最好重载equals和hashCode方法来调用Object的方法,并使用final限定符。
类型安全枚举类的子类必须赋予它自己的序数和提供自己的readResolve方法。也就是说,每个类必须负责它自己实例的序列化和反序列化。
类型安全枚举类的一个缺点就是不方便把类型安全枚举常量聚集到一个集合中。
另外一个缺点就是不能用在switch语句中。加载枚举类和构造常量对象需要一定的时间和空间开销。
22 使用类和接口替换函数指针(Replace function pointers with classes and interfaces)
C语言中的函数指针的主要作用是为了实现Strategy模式。可以定义一个strategy interface来代码所有具体的strategy类。
具体的strategy类通常用匿名类来定义。
可以定义一个host class,通过它来暴露出类型为strategy interface的public static field域(或是静态工厂方法),而具体的strategy类可以是该host类的一个私有嵌套类。
class Host {
private static Class StrLenCmp implements Comparator, Serializable {
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
Return s1.length() – s2.length();
}
}
public static final Comparator STRING_LENGTH_COMPARATOR = new StrLenCmp();
}