Какой дизайн интерфейса библиотеки clojure лучше всего?

Я хочу предоставить несколько реализаций устройства чтения/записи сообщений. Каков наилучший подход?

Вот какой-то псевдокод того, что я сейчас думаю:

  • просто есть набор функций, которые должны быть реализованы всеми реализациями, и оставить его вызывающему, чтобы удерживать нужные потоки.

    (ns x-format)
    (read-message [stream] ...)
    (write-message [stream message] ...)
    
  • возвращает карту с двумя замкнутыми функциями, удерживающимися в потоке

    (ns x-format)
    (defn make-formatter [socket]
      {:read (fn [] (.read (.getInputStream socket))))
       :write (fn [message] (.write (.getOutputStream socket) message)))})
    
  • что-то еще?

Ответ 1

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

Если вы пишете интерфейс, для которого вы ожидаете многих реализаций, рассмотрите возможность использования multimethods. Вы можете по умолчанию выбросить исключение "не реализовано", чтобы заставить разработчиков реализовать интерфейс.

Как Gutzofter, если единственная причина, по которой вы рассматриваете второй вариант, - это позволить людям не вводить параметр при каждом вызове функции, вы можете подумать о том, что все ваши функции используют некоторый var в качестве объекта сокета по умолчанию и пишут макрос with-socket, который использует binding для установки этого значения var. См. Встроенные методы печати, которые по умолчанию используют значение *out* в качестве выходного потока, и with-out-str, который связывает *out* с писателем строки, как пример Clojure.

Эта статья может вас заинтересовать; он сравнивает и противопоставляет некоторые идиомы ООП с эквивалентами Clojure.

Ответ 2

Я думаю, что чтение-сообщение и сообщение-сообщение являются служебными функциями. Что вам нужно сделать, это инкапсулировать свои функции в макро-макро (ы). См. "With-output-to-string" в общем lisp, чтобы видеть, что я имею в виду.

Изменить: Когда вы используете макрос, вы можете иметь обработку ошибок и распределение ресурсов в расширении макроса.

Ответ 3

Я бы включил первый вариант и сделал все эти функции многотомическими.