Ответ 1
Вы видели эту статью? http://stuartsierra.com/2010/01/08/agents-of-swing
Я пишу служебную программу, используя GUI Swing. Я пытаюсь использовать Martin Fowler Модель презентации для облегчения тестирования. Мое приложение автоматически сохранит несколько пользовательских настроек с помощью java.util.prefs.Preferences
(то есть: положение и размер главного окна). Я провел несколько часов в выходные, пытаясь создать Clojure mock API Preferences
(используя EasyMock), чтобы я мог проверить мой код презентатора, но не смог заставить его работать. Clojure Программирование GUI с использованием стиля, отличного от OO, сложно для программиста 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), но не видел этих проблем. Я также изучил Rich Hickey ants.clj
, но его использование Swing в этом примере довольно простое.
Вы видели эту статью? http://stuartsierra.com/2010/01/08/agents-of-swing