Artigo Java Magazine 39 - Interfaces Gráficas com Qualidade

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

Artigo publicado pela Java Magazine 39.

Esse artigo faz parte da revista Java Magazine edição 39. Clique aqui para ler todos os artigos desta edição

Interfaces Gráficas com Qualidade

Parte 2: Presentation Model e a API Binding do JGoodies

Descubra como aplicar o padrão Presentation Model e a API Binding do JGoodies para construir GUIs de alta produtividade que favorecem os testes unitários.

Na primeira parte desta série apresentamos técnicas básicas para um bom projeto visual de interfaces gráficas (GUIs), discutindo questões de organização e posicionamento de elementos que compõem a tela. Criamos também um exemplo demonstrando como a API Forms do JGoodies pode ajudar na construção de GUIs que utilizam componentes Swing.

Nesta segunda e última parte iremos nos aprofundar no código que está por trás da interface e que se comunica com o núcleo do software. Nossa discussão começa tratando de algumas questões que envolvem problemas e necessidades do desenvolvimento de GUIs. Apresentamos o pattern Presentation Model, como uma das estratégias mais eficazes atualmente para o desenvolvimento de aplicações desktop e vemos seu funcionamento detalhado e a contribuição trazida pela API Binding do JGoodies. Ao longo de todo o processo, construímos um exemplo que apresenta diversas características desejadas em aplicações modernas.

Patterns e testes em GUIs

A alta produtividade no desenvolvimento de GUIs em aplicações desktop pode ser alcançada com a ajuda de dois elementos importantes no nível do código: a separação de interesses e a eficácia de testes unitários.

Separação de interesses

A separação de interesses, no nosso caso, significa separar o estado e a lógica da GUI dos componentes gráficos utilizados. Você provavelmente já deve ter ouvido falar em patterns que fazem essa separação, como o Model-View-Controller (MVC), que vem sendo usado tanto no desenvolvimento de aplicações desktop quanto web.

Embora a separação de interesses traga muitas vantagens ao desenvolvimento, ela exige um código específico para sincronizar as variáveis que guardam o estado da GUI com os componentes gráficos. Normalmente as telas recebem objetos de negócio (JavaBeans, por exemplo) do backend do sistema e precisam transferir seus dados para os componentes gráficos e vice-versa. Para que essa conexão entre os dois lados possa ser programada sem muito esforço, precisamos da ajuda de um framework genérico que interligue objetos de negócio e componentes gráficos. Esse é papel da API Binding do JGoodies, que estudaremos nesse artigo.

Eficácia de testes unitários

Outro problema que atinge o desenvolvimento de GUIs é a dificuldade de se construir testes unitários abrangentes e eficazes, que simulam as interações do usuário com a GUI, reproduzindo cliques do mouse e eventos de teclado[1].

Mas será que a separação de interesses não poderia ajudar nessa construção de testes, já que a lógica está separada dos componentes gráficos? Para responder essa pergunta, vamos examinar a Figura 1, que apresenta os três principais patterns para o desenvolvimento de GUIs em aplicações desktop.

 

Figura 1. Estrutura dos principais patterns para GUIs desktop

Observe a estrutura do Model-View-Presenter (MVP) que é uma pequena variação do MVC. O importante a ser observado aqui é o fato de que tanto no MVC quanto no MVP, o controlador (Controller/Presenter) possui uma referência para a visão (View). Assim, para instanciar um controlador dentro de um teste unitário, precisamos da visão com seus componentes gráficos também. Isso faz com que o desenvolvimento de testes unitários ainda continue bastante difícil.

Existe uma solução para contornar esse problema: adicionar uma interface entre o controlador e a visão. Mas não vale a pena explorar essa alternativa quando temos uma terceira opção como o Presentation Model, descrito a seguir.

O pattern Presentation Model

O pattern Presentation Model, também ilustrado na Figura 1, é diferente dos outros apresentados porque quem detém a lógica e o estado da GUI, a classe Presentation Model, não possui uma referência para a classe View. Ocorre exatamente o contrário: é a classe View  que guarda uma referência para a classe Presentation Model. Isso é extremamente valioso na criação de testes.

Estrutura e classes

Quando aplicamos o pattern Presentation Model no desenvolvimento de uma GUI, precisamos criar basicamente três classes (por tela):

·         View – Classe simples que contém os componentes gráficos da GUI. Os dados apresentados na tela refletem o estado mantido pela classe Presentation Model.

·         Presentation Model – Classe que contém o estado e a lógica da GUI. Os dados e variáveis são manipulados em memória, independentemente da existência de componentes e formas de apresentação.

·         Service Layer – Classe que oferece à classe Presentation Model uma comunicação com o mundo exterior, onde serviços externos podem existir (como EJBs, bancos de dados etc.)

 

A separação em classes com diferentes responsabilidades traz vantagens importantes para a implementação e a manutenção da GUI. Quando trabalhamos assim, as classes ficam mais “finas” e consequentemente mais simples, o que facilita o entendimento do código e sua manutenção.

Na verdade, essas vantagens também existem no MVC e no MVP. A grande vantagem no Presentation Model é que não precisamos da classe View para testar a lógica da GUI. Isso permite a criação de testes unitários simples, eficientes e sem a presença de componentes gráficos para atrapalhar.

A API JGoodies Binding

A API Binding do JGoodies oferece um conjunto de classes que simplifica muito a aplicação do pattern Presentation Model. Essa API foi desenvolvida para trabalhar com o JFC/Swing e possui mecanismos para conectar componentes gráficos a variáveis que podem ser manipuladas independentemente de suas formas de apresentação.

Para entender essa idéia, imagine, por exemplo, uma variável booleana que está conectada a um JCheckBox (Figura 2). Sempre que trocarmos o valor dessa variável, o JCheckBox irá refletir a mudança e vice-versa. Ao mesmo tempo, poderíamos conectar outros componentes gráficos a essa mesma variável, por exemplo um JToggleButton. Assim, podemos ter quantos componentes quisermos ligados a uma mesma variável, sendo que a mudança feita em um dos componentes é refletida nos outros.

 

Figura 2. Variável booleana conectada a um JCheckBox e a um JToggleButton.

Uma variável pode conter tanto um valor simples quanto uma lista de objetos. Vamos analisar cada caso separadamente.

Conectando componentes a valores simples

Entre os componentes que podem ser conectados a um valor simples, os principais são JLabel, JTextField, JTextArea, JCheckBox, JRadioButton, JPasswordField e JFormattedTextField. A variável que pode ser conectada a eles é uma implementação da interface ValueModel (pacote com.jgoodies.binding.value), que armazena um valor e o mantém sincronizado com o que é apresentado pelo componente. Ao mudar o valor do ValueModel, o componente refletirá essa mudança. Da mesma forma, se o usuário editar esse valor pela GUI, o ValueModel receberá o valor fornecido.

Existem duas formas de conectar um ValueModel a um componente. Uma opção é utilizar o método estático bind() da classe Bindings (do pacote com.jgoodies.binding.adapter):

 

JTextField textField = new JTextField();

ValueModel valueModel = new ValueHolder();

Bindings.bind(textField, valueModel);

 

Repare que criamos um ValueModel intanciando a classe ValueHolder (do mesmo pacote de ValueModel), que é a implementação que precisamos para esse caso.

A segunda maneira de fazer a conexão é utilizando uma classe de conveniência chamada BasicComponentFactory (também de com.jgoodies.binding.adapter), que possui métodos prontos para criar componentes. Assim, podemos fazer:

 

ValueModel valueModel = new ValueHolder();

JTextField textField =

      BasicComponentFactory.createTextField(valueModel);

 

Essa segunda alternativa será utilizada pelo nosso exemplo por ser mais simples.

Duas questões importantes ainda precisam ser discutidas. Primeiro, o valor mantido pelo ValueModel pode ser lido e alterado através dos métodos getValue() e setValue(). É importante lembrar que para conectar um componente a um ValueModel, o componente precisa conhecer o valor guardado por ele. Portanto, um JCheckBox pode se conectar sem problemas a um ValueModel que guarda um valor booleano, mas não a um que contém um String, por exemplo. Se o ValueModel receber um valor incompatível com o valor esperado pelos componentes conectados a ele, uma exceção será lançada durante a tentativa de conversão.

A outra questão é a emissão de eventos PropertyChangeEvent, que acontece quando é alterado o valor guardado pelo ValueModel. Isso permite que o valor seja “observado” com PropertyChangeListeners. Demonstraremos esse recurso na prática mais adiante.

Conectando componentes a listas de objetos

Os componentes que podem ser conectados a listas de objetos são JComboBox, JList e JTable. A lista de objetos, por sua vez, é representada por um objeto da interface javax.swing.ListModel do Swing, que define métodos para a manipulação da lista e emite eventos quando ela for modificada.

A contribuição do JGoodies Binding foi criar implementações que combinassem a interface ListModel com a simplicidade da interface java.util.List, resultando em duas classes: ArrayListModel (que herda de ArrayList e implementa ListModel) e LinkedListModel (que herda de LinkedList e implementa ListModel). Dessa forma, podemos atuar sobre essas classes dentro da classe "

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?