Подобно Шаблону команд, знакомому нам по объектно-ориентированному программированию, 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