繁体   English   中英

Java 17 个密封类业务用例

[英]Java 17 Sealed Classes Business Use Case

Java 17 引入了密封类,它只允许特定类扩展它们,否则将是最终的

我了解技术用例,但想不出任何现实生活中有用的用例吗?

我们什么时候只希望特定的类能够扩展特定的 class?

在我们自己的项目中,如果我们想要一个新的 class 来扩展密封的 class ,我们不能直接将它添加到允许的类中吗? 在这种情况下,不让 class 成为 final 或 sealed 以避免轻微的开销不是更好吗?

另一方面,当公开一个库供外部使用时,一个密封的 class 如何事先知道它应该允许扩展哪些类?

sealed类提供与开放类(Java 中的默认设置)相反的保证。 一个开放的 class 对实现者说“嘿,你可以子类化我并覆盖我的非final方法”,但它对用户说“我不知道子类是什么样的,所以你只能直接使用我自己的方法”。 另一方面, sealed类对实现者有很大的限制,“你不能子类化我,你只能以这些规定的方式使用我”,但对用户来说非常强大:“我事先知道我所有的子类,所以你知道如果你有一个 me 的实例,那么它必须是 X、Y 或 Z 之一”。 因此,向sealed的 class 添加子类是一项重大更改。

sealed类视为“受限类”而不是“具有超能力的枚举”可能会有所帮助。 Java 中的enum是一组有限的数据值,所有这些都是预先构造的。 sealed class是您提出的一组有限,但这些类可能有无限数量的可能实例。

这是我最近自己写的一个真实示例。 这是在 Kotlin 中,它也有sealed类,但它是相同的想法。 我正在为一些 Minecraft 代码编写包装器,我需要一个 class 来统一表示你在 Minecraft 中的所有死亡方式。 长话短说,我最终将死亡原因分为“被另一个生物杀死”和“所有其他死亡原因”。 所以我写了一个密封接口CauseOfDeath 它的两个实现者是VanillaDeath (将“损坏原因”作为其构造函数参数,基本上是一个列出所有可能原因的枚举)和VanillaMobDeath (将杀死您的特定实体作为其构造函数参数)。

由于这显然是详尽无遗的,所以我将其sealed 如果 Minecraft 以后添加更多死亡原因,它们将属于两个类别之一(“实体死亡”或“其他原因死亡”),因此对我或任何其他人来说再次子类化此接口毫无意义。

此外,由于我对死亡原因的类型提供了非常有力的保证,因此用户根据类型进行区分是合理的。 Java 中的向下转型一直有点代码味道,因为它不可能知道 class 的每个可能的子类。逻辑是“好吧,你已经处理了案例 X 和 Y,但是如果有人来了怎么办并写下你从未听说过的 class Z”。 但这不可能发生在这里。 class 是密封的,因此有人编写一种伪访问者是完全合理的,它为“实体死亡”做一件事,为“其他人死亡”做另一件事,因为 Java(或 Kotlin,在我的例子中)可以是完全相信没有,也永远不会有任何其他可能性。

如果您在 Haskell 或 OCaml 中使用过代数数据类型,这也更有意义。 sealed关键字起源于 Scala,作为一种编码 ADT 的方式,它们正是我刚才描述的:一种类型,定义为有限数量的可能 collections 数据的(标记)联合。 在 Haskell 和 OCaml 中,区分 ADT 以及使用match (或case )表达式是完全正常的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM