我正在编写一个使用Swing GUI的实用程序。我试图使用Martin Fowler的Presentation Model来促进测试。我的应用将自动使用java.util.prefs.Preferences
存储几个用户偏好设置(即:主窗口位置和大小)。我花费了整个周末的时间尝试创建Clojure模拟Preferences
API(使用EasyMock),以便可以测试我的Presenter代码,但无法使其正常工作。对于一个长期使用OO编程风格的程序员来说,使用非OO编程风格的Clojure GUI编程确实很困难。我感觉如果我能发现/开发这些事情的模式(模拟,面向可视化“类”的“接口”等),我就可以在整个应用程序中继续使用相同的模式。
我还使用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
,以便模拟可以替换“真实”版本)来处理首选项,因此没有显示详细信息。我知道蛋糕模式(cake pattern),但在这种情况下,我发现我自己的方法更容易使用。我一直在尝试在Clojure中编写类似的代码。 有哪些开源项目提供了这种类型的好示例? 我已经阅读了几本Clojure书籍(Programming Clojure、The Joy of Clojure、Practical Clojure),但没有看到这些问题的解决方案。 我也研究了Rich Hickey的
ants.clj
,但他在那个示例中对Swing的使用非常基本。