Подобно Шаблону команд, знакомому нам по объектно-ориентированному программированию, Clojure предоставляет мультиметоды и протоколы, которые позволяют разработчикам реализовать такой полиморфизм времени выполнения при формировании абстракций в функциональном стиле и их реализациях. В этой статье блога я продемонстрирую пример, объясняющий, как использовать такой полиморфизм в Clojure.

Чтобы реализовать абстракцию, подобную интерфейсу, Clojure предоставляет defprotocol, функция позволяет нам определять бестелесные абстрактные функции с именем:

Выше я привожу пример такой абстракции с именем «Команда», определяющей функцию без тела, но включающую список параметров и документацию. Как и интерфейсы в Java, функция perform вообще не имеет тела. Но без тела функция не может так многого добиться. Следующий шаг — дать Command тело, чтобы оно ожило с помощью deftype:

deftype реализует абстрактную ➋ perform функцию с телом, тогда как эта реализация вводит другой уровень абстракции между perform и функцией бегуна, я назвал его run ➌. Я точно хочу, чтобы соответствующая функция запуска вызывалась в зависимости от метрики, переданной функции perform в качестве параметра. Например, запущенная реализация «temp» извлекает температуру, тогда как версия «влажность» возвращает влажность в этот день и в указанном городе. Вопрос в том, как Clojure может решить, какую реализацию запуска следует вызывать? Ответ defmultiи defmethod´:

С помощью defmulti я представил мультиметод, который подчеркивает, что функция может иметь несколько реализаций - и это действительно так для различных показателей: температуры, влажности и скорости ветра, и вы можете добавить больше. Первый параметр — это имя мультиметода, а второй — функция-диспетчер. Функция диспетчера является важной, так как она используется для определения того, какая реализация мультиметода должна быть выполнена, воплощенная в defmethod. Итак, какой?

Он регулируется путем сопоставления возвращаемого значения функции диспетчера, значения диспетчеризации при применении к нему параметра команды и строкового литерала в defmethods, заданного в качестве второго параметра. В приведенном выше примере мы вызываем (run metric city day) и давайте предположим, что это команда «temp», функция идентификации возвращает «temp», который соответствует значению отправки, определенному в defmethod, «term», поэтому термин версия функции запуска будет выполняется во время выполнения.

Первоначально опубликовано на bitwise.blog