抽象为代码重用打下了基础。
Clojure语言自身对序列、容器和可调用性进行了抽象:定义Java接口并用Java类实现之。
● 协议(Protocol)作为Java接口的替代物,适于高性能的多态方法调度。
● 数据类型(Datatype)作为Java类的替代物,可用来创建抽象定义的实现,无论该抽象是由协议还是接口定义的。
协议和数据类型提供了一种高性能、灵活的机制,使得采用Clojure进行编程时,不必再为了抽象化编写Java接口,或是为了具体化而编写Java类。
使用协议和数据类型,可以创建新的抽象,以及实现了这些抽象的新类型,更为甚者,还可以将新的抽象扩展至现有类型。
针对抽象编程Clojure的输入输出函数spit(吐)和slurp(吃)建立在两个抽象之上:读和写。
这意味着可以对各种各样的源和目标使用它们,包括文件、URL链接和套接字,并且它们还能被任何人扩展,以支持其他新的类型,无论是那些类型是已经存在的,还是新定义的。
● slurp函数接受一个输入源作为参数,读取其内容,并以字符串的形式返回。
● spit函数接受一个输出目标和一个值作为参数,并把值转换为字符串,然后写入到输出目标。
gulp和expectorategulp和expectorategulp(吞)函数是Clojure中slurp函数的简化版本,而expectorate,则是Clojure中spit函数的缩减版。
gulp 函数从给定的 File 对象创建一个 BufferedReader,随后在它上面进行loop/recur,每次读取一个字符,并追加到一个StringBuilder中,直至到达到输入的末尾,最后返回一个字符串。而基础版本的expectorate函数,甚至比gulp还要更小些。
创建了一个 BufferedWriter 文件,把 content 参数的值转换为字符串,并写入BufferedWriter。
支持其他类型,例如套接字、URL链接和基本输入输出流,需要对gulp和expectorate加以改进,使其能从文件以外的其他数据类型中,生成 BufferedReaders 和 BufferedWriters。所以,创建两个新函数make-reader和make-writer,它们负责以下行为。
● make-reader函数从输入源生成一个BufferedReader。
● make-writer函数从输出目标生成一个BufferedWriter。
make-reader和make-writer只对文件有效,但不久就会有所改变。
只需要更新make-reader和make-writer,就可以使gulp和expectorate支持更多的源和目标了。一种支持更多类型的途径是,使用cond或者condp语句来恰当的处理各种不同类型。
这种方法的问题是,它是封闭的:没有人可以不重写make-reader和make-writer,就能支持新的源和目标类型。
需要的是一种开放的方案,即便代码已然写就,不可更改,其他同伴也能增加对新类型的支持。需要的是两个抽象;一个用于读,一个用于写。