了解Groovy、Scala和Clojure如何将行为融入到Java类中

Java 语言的设计有目的地进行了一定的删减,以避免前代产品中已发现的一些问题。例如,Java 语言的设计人员感觉 C++++ 中的多重继承性带来了太多复杂性,所以它们选择不包含该特性。事实上,他们在该语言中很少构建扩展性选项,仅依靠单一继承和接口。

其他语言(包括 Java 下一代语言)存在巨大的扩展潜力。在本期和接下来的两期文章中,我将探索扩展 Java 类而不涉及继承性的途径。在本文中,您会了解如何向现有类添加方法,无论是直接还是通过语法糖 (syntactic sugar)。

表达式问题

表达式问题是最近的计算机科学历史上的一个众所周知的观察结果,首创于">贝尔实验室的 Philip Wadler 的一篇未发表的论文。(Stuart Sierra 在其 developerWorks 文章 “通过 Clojure 1.2 解决表达式问题” 中出色地解释了它。在这篇文章中,Wadler 说道:

表达式问题是老问题的新名字。我们的目标是通过案例定义数据类型,在这里,在不重新编译现有代码的情况下,您可以将新的案例添加到数据类型和数据类型的新函数中,同时保留静态类型安全(例如,没有转换)。

换句话说,您如何向一个分层结构中的类添加功能,而不求助于类型转换或 if 语句?

我们将通过一个简单的例子来表明表达式问题在真实世界中的表现形式。假设您公司始终假设应用程序中的长度单位为米,没有在您的类中为任何其他长度单位构建任何功能。但是,有一天,您公司与一家竞争对手合并了,而这个竞争对手始终假设长度单位为英尺。

解决该问题的一种方法是,通过使用转换方法扩展 Integer,使两种格式之间的切换变得无关紧要。现代语言提供了多种解决方案来实现此目的;在本期中,我将重点介绍其中的 3 种:

开放类 包装器类 协议

Groovy 的类别和 ExpandoMetaClass

Groovy 包含两种使用开放类 扩展现有的类的不同方式,“重新开放” 一个类定义来实现更改(例如添加、更改或删除方法)的能力。

类别类

类别类(一种借鉴自 Objective-C 的概念)是包含静态方法的常规类。每个方法至少接受一个参数,该参数表示方法扩充的类型。如果希望向 Integer 添加方法,例如我需要接受该类型作为第一个参数的静态方法,如清单 1 所示:

清单 1. Groovy 的类别类

class IntegerConv { static Double getAsMeters(Integer self) { self * 0.30480 } static Double getAsFeet(Integer self) { self * 3.2808 }}

清单 1 中的 IntegerConv 类包含两个扩充方法,每个扩充方法都接受一个名为 self(一个通用的惯用名称)的 Integer 参数。要使用这些方法,我必须将引用代码包装在一个 use 代码块中,如清单 2 所示:

清单 2. 使用类别类

@Test void test_conversion_with_category() { use(IntegerConv) { assertEquals(1 * 3.2808, 1.asFeet, 0.1) assertEquals(1 * 0.30480, 1.asMeters, 0.1) }}

清单 2 中有两个特别有趣的地方。首先,尽管 清单 1 中的扩展方法名为 getAsMeters(),但我将它称为 1.asMeters。Groovy 围绕 Java 中的属性的语法糖使我能够执行 getAsMeters() 方法,好像它是名为 asMeters 的类的一个字段一样。如果我在扩展方法中省略了 as,对扩展方法的调用需要使用空括号,就像 1.asMeters() 中一样。一般而言,我喜欢更干净的属性语法,这是编写特定于域的语言 (DSL) 的一种常见技巧。

清单 2 中第二个需要注意的地方是对 asFeet 和 asMeters 的调用。在 use 代码块中,我同等地调用新方法和内置方法。该扩展在 use 代码块的词法范围内是透明的,这很好,因为它限制了扩充(有时是一些核心)类的范围。

时间: 2024-08-03 22:31:57

了解Groovy、Scala和Clojure如何将行为融入到Java类中的相关文章

Groovy、Scala 和 Clojure 如何将行为融入到类中

Java 语言的设计有目的地进行了一定的删减,以避免前代产品中已发现的一些问题.例如,Java 语言的 设计人员感觉 C++ 中的多重继承性带来了太多复杂性,所以它们选择不包含该特性.事实上,他们在该语言 中很少构建扩展性选项,仅依靠单一继承和接口. 其他语言(包括 Java 下一代语言)存在巨大的扩 展潜力.在本期和接下来的两期文章中,我将探索扩展 Java 类而不涉及继承性的途径.在本文中,您会了解 如何向现有类添加方法,无论是直接还是通过语法糖 (syntactic sugar). 表达式

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(一)

探究这些下一代 JVM 语言如何处理操作符重载 编程语言中的好理念可以延续并扩展到其他语言,就像美酒一样历久弥香.因此,不足奇怪的是,Java 下一代语言 - Groovy.Scala 和 Clojure - 具有很多共同的特性.在本期和下一期 Java 下一代 文章中,我将探讨每种语言语法中功 能清单的一致性.我从能够重载操作符这个特性说起  - 克服了Java 语言中长期存在的一个缺点. 操作符重 载 如果您改造过 Java BigDecimal 类,可能看到过类似于清单 1 的代码: 清单

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(二)

了解Java 下一代语言如何减少样板代码和降低复杂性 Java 编程语言诞生时所面临的限制与如今的开发人员所面临的条件有所不同.具体来讲,由于上世纪 90 年代中期的硬 件的性能和内存限制,Java 语言中存在原语类型.从那时起,Java 语言不断在演化,通过自动装箱(autobox)消除了许 多麻烦操作,而下一代语言(Groovy.Scala 和 Clojure)更进一步,消除了每种语言中的不一致性和冲突. 在这 一期的文章中,我将展示下一代语言如何消除一些常见的 Java 限制,无论是语法上

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(三)

反思异常.表达式和空 在 上一期文章 中,我介绍了 Java 下一代语言用来消除 Java 语言中华而不实的东西和复杂性的创新方式.在这一期 文章中,我将展示这些语言如何消除 Java  的一些瑕疵:异常.语句与表达式,以及围绕 null 的边缘情况. 表达式 Java  语言从 C 语言那里继承的一项传承是区分编程语言 和编程表达式.Java 语句的示例包 括使用 if 或 while 的代码行,以及使用 void 来声明不会返回任何值的方法的代码行.表达式(比如 1 + 2 )用于求取 某一

Groovy、Scala 和 Clojure的使用

在与 Martin Fowler 共同参加的一次主题演讲中,他提供了一个敏锐的观察报告: Java 的遗产是 平台,不是 语言. 最初的 Java 技术工程师曾做过一个了不起的决定,将语言从运行时中分离出来,最终使 200 多种语言可在 Java 平台 上运行.该基础架构对平台保持长久活力非常关键,因为计算机编程语言的寿命通常很短.自 2008 年以来,每年由 Oracle 主办的 JVM 语言峰会都会为 JVM 上替代语言的实现者提供与平台工程师公开合作的机会.   欢迎来 到 Java 下一

Groovy、Scala和Clojure共享的函数结构及其优势

本期文章将展示常见的函数式编程结构在 Java 下一代语言中的表示方式,指出那些功能在实现细节上的一些细微差别. 当垃圾回收成为主流时,它消除了所有类别的难以调试的问题,使运行时能够为开发http://www.aliyun.com/zixun/aggregation/7187.html">人员管理复杂的.容易出错的进程.函数式编程旨在为您编写的算法实现同样的优化,这样您就可以从一个更高的抽象层面开展工作,同时运行时执行复杂的优化. Java 下一代语言并不都占用从命令式到函数式的语言频谱的

有人用Groovy,Scala和Clojure这三种语言吗?他们的前景怎么样?

问题描述 Groovy,Scala和Clojure都是JVM语言,他们和Java的关系是怎样的?是不是对Java的补充,使Java更加灵活?这三种语言的前景如何?哪个值得学一学? 解决方案 解决方案二:Groovy吧有兴趣学习下是对java的一种包装,简化java编写的复杂度

在日益壮大的多语言世界中使用Groovy、Scala和Clojure

在与 Martin Fowler 共同参加的一次主题演讲中,他提供了一个敏锐的观察报告: Java 的遗产是 平台,不是 语言. 最初的 Java 技术工程师曾做过一个了不起的决定,将语言从运行时中分离出来,最终使 200 多种语言可在 Java 平台上运行.该基础架构对平台保持长久活力非常关键,因为计算机编程语言的寿命通常很短.自 2008 年以来,每年由 Oracle 主办的 JVM 语言峰会都会为 JVM 上替代语言的实现者提供与平台工程师公开合作的机会. 欢迎来到 Java 下一代专栏系

将新行为混合到Groovy和Scala类中

Java 语言的开发人员精通 C++ 和其他语言,包括多继承(multiple inheritance),使得类可以继承自任意数量的父类.多继承带来的一个问题是,不可能确定所继承的功能来自哪个父类.这个问题被称为钻石问题(请参阅 参考资料).钻石问题和多继承中固有的其他复杂性启发了 Java 语言设计者选择 "单继承加接口" 的方法. 接口定义了语义,但没有定义行为.它们非常适合用来定义方法签名和数据抽象,所有 Java 下一代语言都支持 Java 接口,并且无需进行重大的修改.不过,