Я пишу служебную программу, используя графический интерфейс 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 в этом примере довольно простое.