Есть аспект сопоставления с образцом, который я не понимаю.
В документации по сопоставлению с образцом они показывают такой пример, как:
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.
Тем не менее, такие двойные стандарты не останутся незамеченными, так что я предполагаю, что с моим пониманием что-то не так.
2 ответа
Под капотом сопоставление с образцом Scala часто сводится к коду, точно похожему на код if (notification instanceof Email) { ... } else if (notification instanceof SMS)
Java.
Конкретный пример, который вы приводите, abstract class Notification
, который не является sealed
, - это тот, где код Scala не лучше (за исключением, возможно, более четкого выражения общего намерения), чем if
/instanceof
дерево.
Это связано с тем, что основным преимуществом сопоставления с образцом является возможность проверки полноты. С подходом if
/instanceof
и приведенным вами примером сопоставления шаблонов вы не будете предупреждены о том, что не обработали каждый случай (например, вы остановили VoiceRecording
кейс).
Сделав Notification
sealed
(например, sealed abstract class Notification
), компилятор Scala гарантирует, что никакой код Scala в других файлах (технически, единицы компиляции, которые по сути являются файлами) не может расширяться. Notification
; поскольку теперь он знает все возможные Notification
, он может вызвать ошибку компилятора, если вы пропустите случай. Нет надежного способа сделать это в случае if
/instanceof
, потому что это более низкий уровень абстракции.
«Запах» был историческим. Объектно-ориентированный дизайн предполагает, что вы должны позволить иерархии типов отправлять вызов вашего метода соответствующему подтипу, а не проверять фактические экземпляры в месте вызова. Было несколько неудачных проектов, связанных с чрезмерным использованием наследования, что привело к такому instanceof
использованию. Использование instanceof
не было чем-то плохим, но намекало на то, что иерархия типов может быть плохой.
С другой стороны, Java 17 теперь также имеет сопоставление с образцом Scala (в качестве функции предварительного просмотра, которая скоро будет доработана), так что нельзя сказать, что использование instanceof
- это плохо в Java.
Похожие вопросы
Связанные вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].