java™ 编程的世界布满了特定于域的语言(DSL),但是在 Java 语言中用来构建 DSL 的选项是有限的。使用 Ruby 则不是这样。在这篇文章中,将学习 Ruby 提供的一些漂亮方式,可以集成干净的 DSL,让您大开眼界,用一种新的参考框架来审阅 Java 的选项。
DSL 是专门解决特定于域问题的语言。通过更接近问题的操作,DSL 可以提供在通用语言中可能找不到的好处。Java 世界中布满了 DSL。属性文件、SPRing 上下文、标注的某种用法以及 Ant 任务,都是 DSL 的示例。
在开始研究其他像 Ruby 这样的语言的时候,我开始理解到 Java 语言目前对于 DSL 还没有良好的把握。在这篇文章中,将看到 Ruby 使用的四种集成干净的 DSL 的技巧。然后,将看到在 Java 语言中可能存在的选项是什么。
关于这个系列
在 跨越边界 系列中,作者 BrUCe Tate 提出了这样一个主张:今天的 Java 程序员通过学习其他技术和语言,会得到很好的帮助。Java 技术是所有开发项目的明显最好选择的情况,在编程领域中已经发生了变化。其他框架正在影响 Java 框架构建的方式,而从其他语言学到的概念也有助于 Java 编程。对 Python(或 Ruby、Smalltalk 等等)代码的编写,可能改变 Java 编码的方式。
这个系列介绍的编程概念和技术,与 Java 开发有根本的不同,但却可以直接适用于 Java 编程。在某些情况下,需要整合这些技术来利用它们。在其他情况下,可以直接应用这些概念。比起其他语言和框架能够影响 Java 社区的开发人员、框架甚至基本方式的理念来说,单独的工具并不那么重要。
隐藏语言的世界
虽然您可能不知道,但实际上您无处不碰到 DSL,从日常生活到使用的应用程序,到您编写的程序。在法庭上,可以看到速记员用 DSL 迅速地进行记录。音乐使用几种不同的标注来描述音量、音调和每个音的时长,采用一种适合特定乐器的格式。(我使用吉它六线谱,里面每条线都代表吉它上的一根弦。)使用 DSL 是因为它们比口述或笔录更能有效地解决问题。
在使用日常的应用程序时,也在使用 DSL。最好的示例是电子表格。编写电子表格,要比使用最简单的会计程序还要轻易。电子表格的 DSL 从根本上改变了为特定问题进行编程的实质。
Java 编程中的 DSL
回头来看,Java 也在到处使用 DSL:
jsp 使得构建定制的用户界面更轻易。
SQL 代表数据库操作。
属性文件代表程序的配置。
xml 描述数据。
XML 描述程序配置,例如在 EJB、Hibernate 或 Spring 中。
XML 描述动作,例如 Ant 任务或某种引擎中的业务规则。
Java 语言并不非凡擅长特定于域的语言,因为这个语言很难按照对 DSL 开发人员来说最有吸引力的方式进行扩展。这就是为什么 XML 这么泛滥的一个原因。XML 是可扩展的,Java 和它的集成很好,可以轻易地构建解释它的工具,而且它也不需要和 Java 类一起编译。但是 XML 对于人类阅读来说很不友好。所以,可以看到对于在 Java 语言中 XML 的过度使用有广泛的抱怨。
使用 Ruby 和活动记录的 DSL
在跨越边界 系列的 第一篇文章 中,您看到了活动记录(Ruby on Rails 背后的持久化引擎)。在这篇文章中,我又回到活动记录,因为它在多个地方对 DSL 概念进行了出色的应用:
特定于域的语句结构和词汇表。 活动记录构建了一个用 Ruby 对象包装关系数据库的词汇表。例如,在数据库支持的对象中,可以用 has_many :people 来构建与另一个数据库支持的对象的一对多关系映射。
扩展类的行为。 根据命名规范,声明叫作 People 的活动记录类,就会拥有与数据库中每个列对应的属性。
修饰现有类型。 Rails 通常修饰 Fixnum 这样的类以提供对域友好的体验。
动态地扩展词汇表。 活动记录提供了一些惊喜,例如根据数据库的结构添加定制查找器。
英语建模。 活动记录根据上下文修改类的复数形式。
随着继续阅读本文,将看到让这些技巧成为可能的 Ruby 特性。您将真正体会到在 Ruby 和 Java 操作方式之间的区别。要跟随本文一起编写代码,需要安装 Ruby 和 Ruby on Rails,其中包含了活动记录(请参阅 参考资料)。