2011-04-11 16 views
13

Estoy escribiendo un programa de utilidad que utiliza una GUI de Swing. Estoy tratando de utilizar Martin Fowler's Presentation Model para facilitar las pruebas. Mi aplicación almacenará automáticamente varias preferencias de usuario usando java.util.prefs.Preferences (es decir, posición y tamaño de la ventana principal). Pasé varias horas durante el fin de semana intentando crear un simulacro de Clojure de la API Preferences (usando EasyMock) para poder probar el código de mi presentador, pero no pude hacerlo funcionar. La programación de la GUI de Clojure que utiliza un estilo que no sea de OO es difícil para un programador de OO de larga duración. Siento que si puedo descubrir/desarrollar patrones para estas cosas (burlas, "interfaces" para "clases" visuales, etc.), puedo seguir usando los mismos patrones en el resto de la aplicación.La programación de Clojure GUI es difícil

También he estado desarrollando la misma aplicación en Scala para comparar los patrones de programación y he encontrado que es mucho más intuitiva, aunque estoy tratando de usar Scala en un estilo funcional bastante estricto (excluyendo, por supuesto, las llamadas a las clases de Java como la Swing API, que tendrá los mismos problemas de mutabilidad en la versión de Clojure, pero, por supuesto, también tendrá un único subproceso).

En mi código de Scala, creo una clase llamada MainFrame que extiende JFrame e implementa el rasgo MainView. MainView expone todos los JFrame llamadas como métodos abstractos que pueda poner en práctica en un objeto de burla:

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) 
    //... 
    } 
} 

estoy usando un pseudo-Singleton (setInstance incluye para que una maqueta puede sustituir a la versión "real") para el Preferencias, por lo que los detalles no se muestran. Sé sobre el patrón de pastel, pero encontré que el mío es un poco más fácil de usar en este caso.

He tenido problemas para hacer un código similar en Clojure. ¿Hay algún buen ejemplo de proyectos de código abierto que hacen este tipo de cosas? He leído varios libros sobre Clojure (Programación Clojure, The Joy of Clojure, Practical Clojure), pero no he visto estos temas tratados. También estudié el ants.clj de Rich Hickey, pero su uso de Swing en ese ejemplo es bastante básico.

Respuesta

5
+0

@dnolen: Sí. Lo volveré a leer. Gracias. Lo que creo que me resulta más difícil es "refactorizar" mi código para funciones en lugar de clases. Es curioso, ya que hice un ** MUCHO ** de programación en C en la década de 1980. – Ralph

+0

@Ralph: en c "función" en la mayoría de los casos significa "procedimiento". De ahí la programación de procedimiento y no funcional :) –

+0

@Vagif Verdi: Sí. Me di cuenta de la diferencia tan pronto como comencé a aprender Clojure, pero la idea de "verbo" en lugar de "sustantivo" también se aplica a la programación de procedimiento C, hasta cierto punto. Después de todo, un "procedimiento" es una serie de operaciones que afectan a los objetos, incluso si esos objetos son realmente un estado imperativo. – Ralph

Cuestiones relacionadas