Дизайн Clojure Model-View-Controller (MVC)
Я пишу приложение с графическим интерфейсом для рабочего стола в Clojure с использованием Java Swing. Обычно при работе с Java я буду проектировать приложение в соответствии с шаблоном проектирования MVC, используя также шаблон Observer. Таким образом, представление отделено от модели, и изменения в любом из них не влияют друг на друга, что облегчает дальнейшие изменения.
Мне было интересно, если Clojure имеет лучший подход к этой проблеме, чем обычные шаблоны проектирования MVC и Observer? Я новичок в функциональном программировании, поэтому я не уверен, как я могу отделить модель от представления. Я требую этого, так как приложение будет разрабатываться итеративно, и могут возникнуть сложные требования, которые могут возникнуть в дальнейшем.
Буду признателен за любую помощь.
Спасибо,
Адам
2 ответа
Многие шаблоны проектирования из мира Java-MVC становятся немного глупыми, когда у вас есть функции первого порядка, макросы (код как данные) и параллельные постоянные структуры данных. например, "шаблон наблюдателя" - это просто агент с несколькими установленными часами. Он идет от шаблона к вызову функции.
если вы сохраняете состояние (модель) в ссылке или агенте и делаете ваше представление функцией (в смысле слова функционального программирования), которая отображает это состояние; делая ваш контроллер функцией (опять же в смысле слова FP), которая создает новое состояние с учетом старого состояния и некоторого нового ввода, тогда модель MVC очень хорошо выпадает.
это немного устарело, но пост макета мешка Стюарта Сьерры действительно помог мне начать работу в этой области.
В 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))))
Также, если вы создаете GUI в Clojure, возможно, стоит взглянуть на некоторые из существующих оболочек библиотеки Swing, например: