Цель диспетчеризации - динамически решать, что делать в вашей функции.
Когда у вас есть (динамическая) диспетчерская функция, ее главная (или единственная, если вам не нужна приведение или другие преобразования) задача - решить, какую другую функцию вызвать. Решение часто основывается на типе экземпляра, к которому вызывается метод, или типе некоторых параметров, но оно также может зависеть, например, от на значение параметра (ов), или некоторые значения конфигурации.
Правило диспетчеризации может быть жестко задано (с использованием, например, сопоставления с образцом в scala) или может быть получено из таблицы диспетчеризации.
Как вы упомянули, есть несколько вариантов, например, одиночная отправка (конкретный метод зависит от экземпляра, в котором вызывается исходный метод, который является базовым механизмом OO), двойная диспетчеризация (отправляет вызов функции различным конкретным функциям в зависимости от типы времени выполнения нескольких объектов, участвующих в вызове). * +1007 *
Связанный шаблон проектирования - Visitor, который позволяет динамически добавлять набор функций к существующим классам и который также имеет динамическую диспетчеризацию в своей основе.
Вложенные блоки / замыкания появляются, когда вы определяете конкретный метод внутри метода отправки или в некотором коде инициализации (например, для таблицы отправки).
Простой пример для случая, когда диспетчеризация основана на значении параметра, с жестко заданным решением и с таблицей диспетчеризации:
class Dispatch {
def helloJohn(): String = "Hello John"
def helloJoe(): String = "Hello Joe"
def helloOthers(): String = "Hello"
def sayHello(msg: String): String = msg match {
case "John" => helloJohn()
case "Joe" => helloJoe()
case _ => helloOthers()
}
val fs = Map("John" -> helloJohn _, "Joe" -> helloJoe _)
def sayHelloDispatchTable(msg: String): String = fs.get(msg) match {
case Some(f) => f()
case _ => helloOthers()
}
}