Дизайн Clojure Model-View-Controller (MVC) - PullRequest
10 голосов
/ 18 января 2012

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

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

Буду признателен за любую помощь.

Спасибо

Адам

Ответы [ 2 ]

11 голосов
/ 18 января 2012

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

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

оно немного устарело, но пост 1009 * макета мешка Стюарта Сьерры действительно помог мне начать работу в этой области.

8 голосов
/ 18 января 2012

В 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, например:

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