为什么在 scala 中模式匹配没问题,但在 Java 中使用 instanceof 是错误代码的标志
Why is pattern matching ok in scala but using instanceof is a sign of bad code in Java
模式匹配有一个方面我不明白。
在模式匹配的文档中,他们展示了一个示例,例如:
https://docs.scala-lang.org/tour/pattern-matching.html
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
def showNotification(notification: Notification): String = {
notification match {
case Email(sender, title, _) =>
s"You got an email from $sender with title: $title"
case SMS(number, message) =>
s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
s"You received a Voice Recording from $name! Click the link to hear it: $link"
}
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
可以在 java 中重新编码,例如:
Notification notification = /* Init a notification instance */
if(notification instanceof Email) {
Email currentEmail = (Email) notification;
currentEmail.doSomething();
} else if (notification instanceof SMS) {
SMS currentSMS = (SMS) notification;
currentSMS.doSomething();
} else if {
/* ... */
}
模式匹配似乎很受欢迎,但相反,java 等价物被视为“代码味道”或错误模式。
据我了解,他们正在做同样的事情,也许在技术上也是如此,它只是隐藏了 scala 模式匹配。
然而这样的双重标准不会被忽视所以我想我的理解有问题。
在幕后,Scala 模式匹配通常归结为与 if (notification instanceof Email) { ... } else if (notification instanceof SMS)
Java 代码完全相同的代码。
您给出的特定示例 abstract class Notification
不是 sealed
,其中 Scala 代码并不比 [=13 更好(除了可能更清楚地表达总体意图) =]/instanceof
树.
这是因为模式匹配的主要好处是可以进行穷举检查。使用 if
/instanceof
方法和您提供的模式匹配示例,您不会被提醒您没有处理所有情况(例如,您离开了 VoiceRecording
例)。
通过Notification
sealed
(例如sealed abstract class Notification
),Scala编译器将确保其他文件(技术上,编译单元,用于所有意图和目的文件)可以扩展 Notification
;因为它现在知道所有可能的 Notification
,所以如果您错过了一个案例,它会引发编译器错误。在 if
/instanceof
情况下没有可靠的方法来执行此操作,因为这是较低的抽象级别。
“气味”具有历史意义。面向对象的设计建议您应该能够让类型层次结构将您的方法调用分派到适当的子类型,而不是在调用站点检查实际实例。有一些与过度使用继承相关的糟糕设计,导致了这种 instanceof
的使用。 instanceof
用法不是坏事,但它暗示类型层次结构可能是坏的。
另一方面,Java 17 now has Scala's pattern matching, too(作为预览功能,即将完成),所以你不能说在 [=18= 中使用 instanceof
是一件坏事].
模式匹配有一个方面我不明白。
在模式匹配的文档中,他们展示了一个示例,例如:
https://docs.scala-lang.org/tour/pattern-matching.html
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
def showNotification(notification: Notification): String = {
notification match {
case Email(sender, title, _) =>
s"You got an email from $sender with title: $title"
case SMS(number, message) =>
s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
s"You received a Voice Recording from $name! Click the link to hear it: $link"
}
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
可以在 java 中重新编码,例如:
Notification notification = /* Init a notification instance */
if(notification instanceof Email) {
Email currentEmail = (Email) notification;
currentEmail.doSomething();
} else if (notification instanceof SMS) {
SMS currentSMS = (SMS) notification;
currentSMS.doSomething();
} else if {
/* ... */
}
模式匹配似乎很受欢迎,但相反,java 等价物被视为“代码味道”或错误模式。
据我了解,他们正在做同样的事情,也许在技术上也是如此,它只是隐藏了 scala 模式匹配。
然而这样的双重标准不会被忽视所以我想我的理解有问题。
在幕后,Scala 模式匹配通常归结为与 if (notification instanceof Email) { ... } else if (notification instanceof SMS)
Java 代码完全相同的代码。
您给出的特定示例 abstract class Notification
不是 sealed
,其中 Scala 代码并不比 [=13 更好(除了可能更清楚地表达总体意图) =]/instanceof
树.
这是因为模式匹配的主要好处是可以进行穷举检查。使用 if
/instanceof
方法和您提供的模式匹配示例,您不会被提醒您没有处理所有情况(例如,您离开了 VoiceRecording
例)。
通过Notification
sealed
(例如sealed abstract class Notification
),Scala编译器将确保其他文件(技术上,编译单元,用于所有意图和目的文件)可以扩展 Notification
;因为它现在知道所有可能的 Notification
,所以如果您错过了一个案例,它会引发编译器错误。在 if
/instanceof
情况下没有可靠的方法来执行此操作,因为这是较低的抽象级别。
“气味”具有历史意义。面向对象的设计建议您应该能够让类型层次结构将您的方法调用分派到适当的子类型,而不是在调用站点检查实际实例。有一些与过度使用继承相关的糟糕设计,导致了这种 instanceof
的使用。 instanceof
用法不是坏事,但它暗示类型层次结构可能是坏的。
另一方面,Java 17 now has Scala's pattern matching, too(作为预览功能,即将完成),所以你不能说在 [=18= 中使用 instanceof
是一件坏事].