| |
Java 理论与实践: 伪typedef反模式 |
|
时间: 2006-03-31 来自:ibm |
 |
|
|
伪类型会传染
这种
“病毒” 性质是让 C 代码的重用有困难的因素之一。差不多每个 C 包都有头文件,定义工具宏和类型,像
int32、boolean、true、false,诸如此类。如果想在一个应用程序内使用几个包,而它们对于这些公共条目没有使用相同的定义,那么即使要编译一个只包含所有头文件的空程序,之前也要在
“头文件地狱” 问题上花好长时间。如果编写的 C 应用程序要使用许多来自不同作者的不同的包,那么几乎肯定要涉及一些这类痛苦。另一方面,对于 Java
应用程序来说,在没有这类痛苦的情况下使用许多甚至更多的包,是非常常见的事。如果包要在它们的 API
中使用伪类型,那么我们可能就要重新经历早已留在痛苦回忆中的问题。
作为示例,假设有两个不同的包,每个包都用伪类型反模式定义了
StringList,如清单 4 所示,而且每个包都定义了操作 StringList
的工具方法。两个包都定义了同样的标识符,这一事实已经是不方便的一个小源头了;客户程序必须选择导入一个定义,而另一个定义则要使用完全限定的名称。但是更大的问题是现在这些包的客户无法创建既能传递给
sortList 又能传递给 reverseList 的对象,因为两个不同的 StringList
类型是不同的类型,彼此互不兼容。客户现在必须在使用一个包还是使用另一个包之间进行选择,否则他们就必须做许多工作,在不同类型的 StringList
之间进行转换。对包的作者来说以为方便的东西,成为在所有地方使用这个包的突出障碍,除非在最受限的环境中。
清单 4.
伪类型的使用如何妨碍重用
伪类型通常太具体
伪类型反模式的进一步问题是,它会丧失使用接口定义变量类型和方法参数的好处。虽然可以把
StringList 定义成扩展 List<String> 的接口,再定义一个具体类型 StringArrayList 来扩展
ArrayList<String> 并实现 StringList,但多数伪 typedef
反模式的用户通常达不到这种水平,因为这项技术的目的主要是为了简化和缩短类型的名称。但结果是,API 的用处减少了并变得更脆弱,因为它们使用 ArrayList
这样的具体类型,而不是 List 这样的抽象类型。
更安全的技巧
一个更安全的减少声明泛型集合所需打字量的技巧是使用类型推导(type
inference)。编译器可以非常聪明地使用程序中内嵌的类型信息来分配类型参数。如果定义了下面这样一个工具方法:
public static <K,V> Map<K,V> newHashMap() {
return new HashMap<K,V>();
}
| 那么可以安全地用它来避免录入两次参数:
Map<Socket, Future<String>> socketOwner = Util.newHashMap();
| 这种方法之所以能够奏效,在于编译器可以根据泛型方法 newHashMap()
被调用的位置推导出 K 和 V 的值。
结束语
伪 typedef 反模式的动机很简单 ——
开发人员想要一种方法可以定义更紧凑的类型标识符,特别是在泛型把类型标识符变得更冗长的时候。问题在于这个做法在使用它的代码和代码的客户之间形成了紧密的耦合,从而妨碍了重用。不喜欢泛型类型标识符的冗长是可以理解的,但这不是解决问题的办法。
|
|
|
|
|
|
|
|