Clojure Модель-View-Controller (MVC)

Я пишу приложение Desktop GUI в Clojure с помощью Java Swing. Обычно при работе с Java я буду разрабатывать приложение в соответствии с шаблоном проектирования MVC с использованием шаблона Observer. Таким образом, вид отделяется от модели, и изменения ни в одном не влияют друг на друга, что облегчает дальнейшие изменения.

Мне было интересно, имеет ли Clojure лучший подход к этой проблеме, чем обычный шаблон проектирования MVC и Observer? Я новичок в функциональном программировании, поэтому я не уверен, как я могу сделать модель отдельной от представления. Я требую этого, так как приложение будет разрабатываться итеративно, и могут возникнуть сложные требования, которые идут дальше по линии.

Поблагодарили бы за любую помощь.

Спасибо,

Адам

Ответ 1

Многие шаблоны проектирования из мира Java MVC становятся немного глупыми, когда у вас есть функции первого порядка, макросы (код-данные) и параллельные постоянные структуры данных. например, "шаблон наблюдателя" - это просто агент с некоторыми наборами часов. Это от шаблона вызова функции.

если вы сохраняете состояние (модель) в ref или агенте и делаете свое представление функцией (в смысле функционального программирования слова), которая отображает это состояние; делая ваш контроллер функцией (опять-таки в смысле FP слова), который создает новое состояние, учитывая старое состояние и некоторый новый вход, тогда модель MVC выпадает очень красиво.

он немного устарел, но Stuart Sierra расположение макета сетки действительно помог мне начать работу в этой области.

Ответ 2

В Clojure вы, безусловно, можете сделать MVC, но я бы предложил реализовать его с помощью часов на Clojure ссылках.

Код будет выглядеть примерно так:

; define the model as an immutable structure stored in a ref
(def model (ref (create-my-model)))

; function to update the UI when the model changes
(def update-function [old-model new-model]
  (do-whatevever-updates old-model new-model))

; add a watch to the model to call update-function when a change happens
(add-watch model :on-update
  (fn [key reference old-state new-state]
    (if (not= old-state new-state)
      (update-function old-state new-state))))

Также, если вы создаете графический интерфейс в Clojure, возможно, стоит взглянуть на некоторые из существующих оболочек Swing-библиотеки, например:

  • Clarity - имеет хороший DSL для определения элементов пользовательского интерфейса.
  • Seesaw - возможно, самая зрелая оболочка для Swing
  • clj-swing