Есть аспект сопоставления с образцом, который я не понимаю.

В документации по сопоставлению с образцом они показывают такой пример, как:

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
Robert Reynolds 2 Фев 2022 в 18:37
Возможно полезно: stackoverflow.com/questions/754166/…
 – 
Chris
2 Фев 2022 в 18:43
Это довольно новое в java.
 – 
Thorbjørn Ravn Andersen
2 Фев 2022 в 18:44
 – 
Luis Miguel Mejía Suárez
2 Фев 2022 в 18:44

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, потому что это более низкий уровень абстракции.

6
Levi Ramsey 2 Фев 2022 в 21:37

«Запах» был историческим. Объектно-ориентированный дизайн предполагает, что вы должны позволить иерархии типов отправлять вызов вашего метода соответствующему подтипу, а не проверять фактические экземпляры в месте вызова. Было несколько неудачных проектов, связанных с чрезмерным использованием наследования, что привело к такому instanceof использованию. Использование instanceof не было чем-то плохим, но намекало на то, что иерархия типов может быть плохой.

С другой стороны, Java 17 теперь также имеет сопоставление с образцом Scala (в качестве функции предварительного просмотра, которая скоро будет доработана), так что нельзя сказать, что использование instanceof - это плохо в Java.

0
Lukas Eder 2 Фев 2022 в 21:58