4.7 例子:Java和Unix I/O
Last updated
Last updated
今天最明显的类炎的例子之一是Java类库。Java语言不需要大量的小类,但类炎的文化似乎已经在Java编程界扎根了。例如,为了打开一个文件,以便从中读取序列化对象,你必须创建三个不同的对象。
FileInputStream
对象只提供基本的I/O:它不能执行缓冲I/O,也不能读写序列化的对象。BufferedInputStream
对象为FileInputStream
增加了缓冲功能,而 ObjectInputStream
增加了读写序列化对象的能力。上述代码中的前两个对象,fileStream
和 bufferedStream
,一旦文件被打开就不会被使用;所有未来的操作都使用 objectStream
。
特别令人讨厌(而且容易出错)的是,必须通过创建一个单独的BufferedInputStream
对象来显式地请求缓冲;如果开发者忘记创建这个对象,就不会有缓冲,I/O就会很慢。也许Java开发者会争辩说,不是每个人都想在文件I/O中使用缓冲,所以它不应该被建立在基本机制中。他们可能会争辩说,最好把缓冲分开,这样人们就可以选择是否使用它。提供选择是好的,但是接口的设计应该使普通情况尽可能简单(见的公式)。几乎每一个使用文件I/O的用户都会想要缓冲,所以应该默认提供缓冲功能。对于那些不希望有缓冲的少数情况,库可以提供一种机制来禁用它。任何禁用缓冲的机制都应该在接口中干净地分开(例如,为FileInputStream
提供一个不同的构造函数,或者通过一个禁用或替换缓冲机制的方法),这样大多数开发者甚至不需要意识到它的存在。
相比之下,Unix系统调用的设计者使普通情况变得简单。例如,他们认识到顺序I/O是最常见的,所以他们将其作为默认行为。而通过使用lseek
系统调用,随机访问仍然是比较容易做到的,但是只需要顺序访问的开发者不需要意识到这种机制。如果一个接口有很多特性,但大多数开发者只需要知道其中的几个,那么这个接口的有效复杂性就只是常用特性的复杂性。