Программирование на Clojure GUI сложно - PullRequest
13 голосов
/ 11 апреля 2011

Я пишу служебную программу, используя графический интерфейс Swing.Я пытаюсь использовать презентационную модель Мартина Фаулера для облегчения тестирования.Мое приложение автоматически сохранит несколько пользовательских настроек, используя java.util.prefs.Preferences (то есть: положение и размер основного окна).В выходные я потратил несколько часов, пытаясь создать имитацию Clojure для Preferences API (используя EasyMock ), чтобы я мог протестировать свой код докладчика, но не смог заставить его работать.Программирование с использованием Clojure GUI с использованием не OO-стиля сложно для ОО-программиста.Я чувствую, что если я смогу обнаружить / разработать шаблоны для этих вещей (насмешки, «интерфейсы» для визуальных «классов» и т. Д.), Я смогу продолжать использовать те же шаблоны в остальной части приложения.

Я также разрабатывал то же приложение в Scala для сравнения шаблонов программирования и обнаружил, что оно гораздо более интуитивно понятно, хотя я пытаюсь использовать Scala в довольно строгом функциональном стиле (исключая, конечно, вызовы таких классов Java, какSwing API - который будет иметь те же проблемы с изменяемостью в версии Clojure, но, конечно, также будет однопоточным).

В моем коде Scala я создаю класс с именем MainFrame, который расширяетJFrame и реализует черту MainView.MainView выставляет все вызовы JFrame как абстрактные методы, которые я могу реализовать в фиктивном объекте:

trait LabelMethods {
  def setText(text: String)
  //...
}

trait PreferencesMethods {
  def getInt(key: String, default: Int): Int
  def putInt(key: String, value: Int)
  //...
}

trait MainView {
  val someLabel: LabelMethods
  def addComponentListener(listener: ComponentListener)
  def getLocation: Point
  def setVisible(visible: Boolean)
  // ...
}

class MainFrame extends JFrame with MainView {
  val someLabel = new JLabel with LabelMethods
  // ...
}

class MainPresenter(mainView: MainView) {
  //...
  mainView.addComponentListener(new ComponentAdaptor {
    def componentMoved(ev: ComponentEvent) {
      val location = mainView.getLocation
      PreferencesRepository.putInt("MainWindowPositionX", location.x)
      PreferencesRepository.putInt("MainWindowPositionY", location.y)
  }
  mainView.someLabel.setText("Hello")
  mainView.setVisible(true)
}

class Main {
  def main(args: Array[String]) {
    val mainView = new MainFrame
    new MainPresenter(mainView)
  }
}

class TestMainPresenter {
  @Test def testWindowPosition {
    val mockPreferences = EasyMock.mock(classOf[PreferencesMethods])
    //... setup preferences expectation, etc.
    PreferencesRepository.setInstance(mockPreferences)

    val mockView = EasyMock.createMock(classOf[MainView])
    //... setup view expectations, etc.
    val presenter = new MainPresenter(mockView)
    //...
  }
}

Я использую псевдо-синглтон (setInstance включен, чтобы макет мог заменить«реальная» версия) для предпочтений, поэтому детали не отображаются.Я знаю о шаблоне тортов, но мне показалось, что использовать его немного проще в этом случае.

Я боролся с созданием подобного кода в Clojure.Есть ли хорошие примеры проектов с открытым исходным кодом, которые делают подобные вещи?Я прочитал несколько книг по Clojure (Программирование Clojure, Радость Clojure, Практическое Clojure), но не видел, чтобы эти проблемы решались.Я также изучил Рич Хики ants.clj, но его использование Swing в этом примере довольно простое.

1 Ответ

5 голосов
/ 11 апреля 2011

Вы видели эту статью? http://stuartsierra.com/2010/01/08/agents-of-swing

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...