MVC - PADROES - Criando um para APLICACOES DESKTOP

:smiley:

Ola Senhores, senhoras.

Boa noite, recentemente iniciei meus estudos em java, e vi q existe um universo maravilhoso, mas complexo, cheio de recursos. { java, write once, run everywhere? } isso é otimo. Porem os tutorias e artigos nao ajudam nos entendimentos necessarios, veja bem, sou Analista e Programador DELPHI a 8 anos, fiz muita coisa e é uma linguagem interessante, tem sua limitacoes. Bom eu gostaria que a turma dos
experts nos ajudasse a definir um padrao MVC, pra desktop, o modelo
basico é :

Usuario --<>-- GrupoUsuario

sendo que :

Usuario :
CodUsu int 10
NomUsu string 60
CodGrp int 10

GrupoUsuario :
CodGrp int 10
DesGrp string 60

Intao, precisamos aplicar MVC, mas como ?

1° vamos tentar definir pacotes
2° vamos definir as classes Model View e Control

alguem se habilita ?

Ola gladson…

Bom, os dados que você deu dizem respeito apenas a camada de Modelo…

Portanto você deverá ter algo como uma classe pra representar um usuário, e uma classe pra representar um grupo de usuarios…

A partir daí, voce deve separar as classes que irão gerar a camada de visualização, se é desktop, provavelmente você irá usar SWT, AWT ou mais provavelmente Swing.

E então irá fazer outras classes que serão responsáveis por trafegar a informação do modelo para a visualização, que é a camada de controle.

Exemplo simples:

Uma classe, representa uma janela em swing, que tem um formulário de cadastro de usuário (visualização). Ao apertar um botão nesta janela, chamará uma classe que será responsável por pegar os dados do formulário e chamar a classe do modelo responsável por persistir (gravar) estes dados, e retornar se tudo ocorreu bem. E porfim, o controlador retorna esta mensagem para alguma classe da camada de visualização.

A primeira coisa q vc deve fazer eh dar uma olhada no GoF pattern Observer. Vc registra sua classe de interface com o usuario - no linguajar do Delphi, seu Form ou seus edits - como observer do “model”, no seu caso Usuario ou GrupoUsuario. A cada mudanca de estado do seu Usuario ele notifica seus observers (as classes de interface com o usuario nesse caso) q sao atualizadas para exibir o estado atual da classe Usuario (Id, Nome, etc…)

O MVC parece meio complexo a principio, principalmente pra quem veio de tecnicas de desenvolvimento procedurais - como foi o meu caso e parece ser o seu tbm. Mas logo vc vai descobrir q ele nao eh nem um bicho de sete cabecas, pelo menos em aplicacoes desktop.

:smiley:

Gente que legal, vlw as respostas.

Mas eu to sentindo muito tecnico, e nada de pratica !!
Estou enganado ?
Acho muito lindo os termos, mas acho q podemos mostrar coisas mais praticas.

:lol:

Valeu
estou aguardando !!!

Qual exatamente eh sua duvida?

Vou tentar dar uma explicacao geral.

Comecamos com as interfaces:

Vou fazer com a sintaxe em Object Pascal talvez seja mais facil pra vc.

primeiro o subject (seu modelo a ser observado, no seu caso a classe usuario)

unit …

uses…

type IObservado = Interface

procedure addObserver(IObserver o);
procedure removeObserver(IObserver o);
procedure notificaObserver;
end;

a interface Observer

unit…

uses…

type IObserver = Interface

procedure atualiza();
end;

A sua classe “model” implementa a interface subject.

unit…
uses…
type Usuario = class (TInterfacedObject, IObservado)
private
//seus atributos…
public
//seus metodos e os metodos da interface
public addObserver(IObserver o);
public removeObserver(IObserver o);
public notificaObserver();
end;

implementation

//os metodos da sua classe aqui

//depois os metodos da interface
procedure Usuario.addObserver(Iobserver o)
begin
//adiciona um observer a uma lista de objetos
//fazer isso em Delphi eh um saco
//em java eh mais facil com os generics
end;

procedure Usuario.removeObserver(IObserver o)
begin
//remove os observers da lista
end;

procedure Usuario.notifica
begin
//notifica todos os usuarios da lista
//chamando o metodo “atualiza” de todos eles
end;

Depois sua classe UI implementa a interface observer
e o metodo atualiza realiza as alteracoes q vc precisa no seu Form/Edit/qqr compeonente visual.

isso que eu estava procurando.
http://www.cti.furg.br/~carlos/down/2007-1/bd/Documentos%20-%20Arquitetura%20MVC%20em%20Aplicacoes%20Desktop.pdf

:lol:

Swing por si só, sendo bem “modelado” já implementa MVC.

Qual sua dúvida?

Na verdade, Swing é M VC. Ou seja, o controller está junto com a view. Não é MVC puro.

Por exemplo, um JPanel pode implementar um listener, ouvir eventos e controlar a interação entre seus componentes.

Gladson, vi ultra-rápido o artigo que você colocou e não sei se isso é bem o que você está procurando. É quase 100% de certeza que você não irá precisar dos padrões DTO e BO.

Implementa alguma coisa e publica aqui pra gente brincar. :smiley:

:smiley:

Ops

Rafael, veja a minha primeira postagem e tente montar aqui pra nos algo

:wink:

Olá.

Eu postei isso em outro tópico há algumas horas, mas volto a reproduzir aqui. É um approach bem simplista, mas funcional.

Model class Model extends Observable { private Usuario atual; private List<Usuario> list; ... public Usuario proximo() {} public Usuario anterior() {} public Usuario atual() {} ... public void setUsuario(Usuario u) { ... setChanged(); notifyObservers(); } }
Controller [code]
public class ProximoAction extends AbstractAction implements Action {
private Model model;
private View view; //pode ser necessario para extrair dados.

public ProximoAction(Model m, View v) {…}

public void actionPerformed(ActionEvent evt) {
model.setUsuario(model.proximo()); //gera um evento na interface
}
}[/code]
View [code]
public class View extends JFrame {
private Model model;

public View (Model m) {
this.model = m;
model.addObserver(this); //registra-se como “observador”
}

public void construirJanela() {
jButtonProximo = new JButton();
jButtonProximo.setAction(new ProximoAction(this.model, this)); //instancia o controller
}

public void update(Observable obs, Object obj) {
//mudou o usuario ‘atual’ do modelo
//atualizar campos na tela usando dados do usuario atual
Usuario u = this.model.atual();
}
}[/code]

[quote=bzanchet]Note que este approach é bem simplista, e dificilmente seria suficiente para sistemas maiores e mais complexos. E eu nem fiz a camada de persistência.
Podem ser necessários eventos e listeners mais especializados, pode ser necessário que a própria camada de apresentação mantenha um estado (http://www.martinfowler.com/eaaDev/PresentationModel.html). Pode-se optar por responsabilizar o controller pela atualização da camada de apresentação. Pode-se usar algum framework para fazer “binding” automático (https://binding.dev.java.net/ - https://genesis.dev.java.net/).
Mas… bom… não vou escrever um livro. Não aqui, agora. :D[/quote]

Rafael, discordo do fato do swing “ser” M-VC. Como disse no exemplo, é possível separar o controller da view, usando javax.swing.Action ao invés de Listeners. Na implementação que mostrei, de diferente do MVC “clássico”, apenas o fato de haver uma dependência (circular) View --> Controller.

Mas, gladson, é importante ressaltar que Model, View e Controller não são “classes”. São “agrupamentos” de classes com responsabilidade semelhante. Volto a indicar o artigo: http://fragmental.com.br/wiki/index.php?title=MVC_e_Camadas .

[]s
Bruno

[quote=gladson] :smiley:

Ops

Rafael, veja a minha primeira postagem e tente montar aqui pra nos algo

:wink:[/quote]
Não, senhor.

Gladson, como eu disse antes, tente implementar primeiro para depois a gente tentar te ajudar.

Usar Action’s como Controller pra mim é um pouco estranho. Eu os utilizo apenas como Command, o que pode criar uma dependência com a view (assim como no seu exemplo), mas não com o model. [code]
public final class CreateEntity extends AbstractAction {

private final Form form;

private static final String ACTION = &quot;cadastrar_entidade&quot;;

private static final String SHORT_DESCRIPTION = &quot;Cadastra entidade no banco de dados&quot;;

private static final String LARGE_ICON = &quot;/iboi/gui/cadastro/resources/save21.png&quot;;

public CreateEntity(Form form) {
    super();
    putValue(Action.SHORT_DESCRIPTION, SHORT_DESCRIPTION);
    putValue(Action.ACTION_COMMAND_KEY, ACTION);
    putValue(Action.LARGE_ICON_KEY, new ImageIcon(
            this.getClass().getResource(LARGE_ICON)));
    this.form = form;
}

public void actionPerformed(final ActionEvent e) {
    form.create();
}    

}
[/code]
Note que se você utilizar a anotação @Action do Swing Application Framework como alternativa à criação de sublcasses concretas de Action, seu método model.setUsuario(model.proximo()) terá que obrigatoriamente ser chamado dentro da view, que no final agirá como controller também.

Se você ver os componentes Swing, verá que JList, por exemplo, é view e controller. Não há nehuma classe fazendo "uma ponte" entre JList e seus models. O próprio JList cuida disso.

Essa "diferença" é "a diferença". Antes de discutirmos sobre o que você fez, por que não diz se você sempre faz isso, se há ganhos nessa abordagem?

A princípio, não vi nenhuma. Muito ao contrário, dependências circulares são “mal-vindas” e eliminá-las costuma dar um certo trabalho. Mantê-las, mais trabalho ainda.

Mas foi interessante ver essa separação. Nunca tinha pensado em fazer algo do gênero.

Olá!

Não, eu não “faço sempre isso”. Só tentei imaginar uma abordagem o mais próximo possível do MVC clássico para mostrar (no outro tópico). É tão simplista que é praticamente inútil. :slight_smile:

Bom, eu não gostaria de entrar numa discussão teórica e perder o rumo, que, afinal, é chegar a um consenso sobre qual o melhor balanço entre separação de responsabilidades e “a coisa toda funcionando”.

Entretanto, preciso adicionar esse detalhe: eu discordo quando dizes que alguns componentes do swing “são view e controller”. Ao meu ver, JList, JTable e outras classes que funcionam com um “model” próprio (eg.: TableModel, ListModel) não são exemplos de “M VC”, mas sim exemplos de PresentationModel, que é quando o próprio componente gráfico mantém um estado. Nada impede que este componente “inteiro” seja colocado na camada de apresentação de uma aplicação MVC “clássica” (quando eu falo “MVC clássico” me refiro ao diagrama tradicional, com a view “puxando” os dados do model). E nesse contexto, o TableModel ou ListModel tem acesso ao modelo propriamente dito, do MVC, onde ele obtém os dados. Não sei se me fiz entender… Talvez com código ficasse melhor.

Voltando ao assunto: essa dependência circular no meu código é um dos vários tradeoffs que cada decisão inclui. A dependência circular pode ser eliminada se a camada de apresentação expôr os seus componentes (assim, o próprio controller faria o registro - view.getButtonX().setAction(this)) e teríamos o diagrama clássico. Entretanto, a quantidade de código aumenta sensivelmente, e ainda dificulta o uso de editores visuais (pelo menos os que eu testei). Além disso, esse código cheiraria mal, pior do que o anterior, não achas? :smiley:

Aliás, as três opções discutidas - juntar view e controller, separar o controller usando Actions com e sem dependência circular - têm as suas vantagens e desvantagens. Achas que alguma delas é sensivelmente superior às demais?

Outra coisa: se controller e view são fortemente acoplados (e são, nas 3 abordagens), qual é o grande problema em ter aquela dependência circular?

Abraço,
Bruno

Vamos começar por aqui que está mais fácil. Sim, eu acho, mas não tenho certeza, muito menos como afirmar isso com todas as letras.

Eu tenho pensado em como criar uma boa arquitetura Swing praticamente todos os dias no último ano e meio e finalmente consegui alcançar uma que me contentou, na semana passada (ufa!). Mas assim que terminei fiquei imaginando se há outras arquiteturas, alternativas igualmente robustas, e quais seriam os pontos fracos do que acabei de fazer. Daí você apareceu com uma proposta interessate.

Com “boa arquitetura” aqui, quero dizer: algo que resulte em não repetir código e fácil manutenção (correção de bugs e, principalmente, adicionar/modificar novas funcionalidades e regras de negócios). [EDITADO]E que trabalhe bem com o NetBeans 5.0 + .[/EDITADO]

Bruno, mas a questão nunca foi o model, mas o controller. O controller que você deixou de fora com o seu diagrama show de bola pode existir. Mas para Swing funcionar estritamente como MVC, deveria haver outro controller entre o JTable e o TableModel, não?

Vou dizer como a coisa toda funciona por aqui para não ficar tão teórico. Imagine uma tela de cadastro, com uma lista de entidades acima, o formulário para cadastro no centro e uma toolbar para diversos comandos, como os CRUD, pesquisa etc.

A única coisa que muda entre as várias GUI’s de cadastros é o formulário. Então temos uma classe abstrata com todos os componentes e comportamentos em comum, e subclasses concretas que apenas “plugam” o formulário específico, representados pela interface Form. public interface Form&lt;T&gt; { void create(); void update(); void setEntity(T entity); void clear(); T getEntity(); T updateSelectedEntity(T entity); }
Esse painel (a GUI de cadastro) age como view (claro!) e como controller, porque escuta a seleção na lista, obtém a entidade e a passa para o formulário se virar e mostrar os dados. A lista partilha o mesmo model que o fomulário. Esse model implementa javax.swingAbstractListModel e FormModel: public interface FormModel&lt;T&gt; { void load(); void addEntity(T entity); void updateEntity(T entity); void removeEntity(T entity); }
E é esse model que finalmente se comunica com a camada de negócio (serviços, domain model), além de encapsular (wrapper) os objetos de domínio. Percebeu que está tudo genérico? O model descobre com qual componente de serviço deve conversar em runtime, e o obtém através de factories.

Ainda tenho algumas questões quanto a sua abordagem, que são mais dúvidas do que críticas:

  1. Implementar controller como javax.swing.Action não é uma furada? Porque Action’s não foram feitos pra isso (na boa, os engenheiros Swing não fizeram a mínima questão de separar o V do C). E quando alguém me diz Action, imediatamente eu lembro de Command, nunca de controller. Como um dos objetivos dos patterns é melhorar a comunicação, controllers em Actions são contra-intuitivos, dificultando aprendizagem e manutenção, certo?

  2. Eu imagino que para cada botão ou menu haverá um controller implementado como Action, o que pode levar a muita duplicação de código e difícil manutenção.

  3. E quando um listener, e não um Action (Command), for realmente necessário, como no caso acima onde a GUI escuta a lista?

[text style=“drama” hiperbole=“on”]
Errr… não sei. Sempre que o FindBugs aqui detecta uma, eu começo a suar litros e litros e não descanso um segundo até eliminá-las.
[/text]
De modo que não sei na prática se podem causar algum problema futuro. Eu optei por não pagar pra ver.

Bruno, você ainda não respondeu… [quote=RafaelRio]se há ganhos nessa abordagem?[/quote]
Digo, esse esforço para ter o “MVC clássico” é um exercício mental, ou funciona no dia-a-dia com êxito? É sempre bom ter boas alternativas. Se a minha abordagem aqui não for adeqüada para certa ocasião, posso tentar a sua (plano B).

See ya!

Esta afirmação é incorrecta. Swing implementa sim MVC . M são os models como o TableModel , DOcument, ListModel , etc… C o controller é o componente o JTable, o JTexfField o JList etc… V , o view são as classe de que derivam de ComponentUI. O Controller não está junto com a view. Já que vocè pode mudar a view (tem um setUI() para vc mudar a view). O que acontece é que essa tarefe é delegada ao L&F que é um mecanismo que funciona em cima do MVC.

Todo o JComponent tem um ComponentUI e um modelo. MCV mais puro que este não existe.

[quote]Há ganhos nessa abordagem?[/quote]Desculpe a decepção, mas a resposta é um “não sei”. Nunca usei em algum sistema complexo o suficiente. Mas acho que pagaria pra ver. :?

[quote]Mas para Swing funcionar estritamente como MVC, deveria haver outro controller entre o JTable e o TableModel, não?
(na boa, os engenheiros Swing não fizeram a mínima questão de separar o V do C)[/quote]
[editado]Ver o post anterior.[/editado]
Entretanto, abstraindo o V do swing e olhando do ponto de vista da nossa aplicação, talvez o que chamas de M-VC eu chame de ModelPresenter, e estamos falando da mesma coisa.

Pensando bem, realmente esse nome Action foi uma escolha ruim. Mas perceba, o java.swing.Action é uma extensão dos Listeners - que são controller por natureza. Deveríamos evitar o uso só por causa do nome? Ainda me parece uma maneira interessante de tirar o controller de dentro da camada de apresentação de uma aplicacação swing.

É exatamente o contrário! Haverá uma Action para cada funcionalidade diferente, e elas podem ser reaproveitadas (sem modificações) em componentes gráficos com a mesma função. Não consigo imaginar um exemplo que torne necessário duplicar código. Pelo contrário, usando listeners na view, imagine que haja dois botões que façam a mesma coisa. Ou duplica-se código, ou tu faz um terceiro método (além dos dois actionPerformed) pra encapsular aquela funcionalidade. Claramente a segunda opção é menos pior, porém ela “engorda” a camada de apresentação. Mas é justamente isso que estamos tentando evitar ao usar MVC, lembra?

O método setAction(Action a) de cada componente registra a ação com seu evento “principal”. O clique no botão, o no textfield etc. Havendo necessidade, não há problema em escrever um listener específico (eg: ListSelectionListener) dentro da camada de apresentação, e delegar para a Action correspondente (que fica na camada controller).

Se entendi sua solução, todo o código que postasse (FormModel, Form e os respectivos ConcreteFormModelT’s e ConcreteFormT’s) fica dentro da camada “VC”. OK. Não é aí que divergimos. Esses seriam só mais componentes ModelPresenter, especializados!

O que eu propus foi que os listeners dos componentes existentes na classe da janela (deve ser uma classe bem gorda, não?) fossem colocados em subclasses de Action (SaveAction, DeleteAction etc), em outra camada. O que usas hoje? Anonymous inner classes gerados pela IDE? No final, a diferença nem é assim tão grande. :smiley:

Abraço,
Bruno

É mesmo, não deve ter tanta diferença assim. :-o Talvez a maior divergência seja com relação ao Action.

É que pra mim (Action != Observer) && (Action == Command).
Definição de Command:

Promote “invocation of a method on an object” to full object status

An object-oriented callback

Referência aqui.

Até aí concordo plenamente. Eu faço uso de Actions em botões e menus, inclusive postei , algumas mensagens atrás, um exemplo dos meus Actions, que chamei de CreateEntity ao invés de SaveAction. Dessa forma, minha GUI principal não fica assim gorda. :slight_smile:

Não mesmo. A maior diferença está em como encaramos e usamos javax.swing.Action. :roll: Compara o que postei com o que você publicou, aqui nesse mesmo tópico.

Abraços!

A View cria um Objeto.

View passa o Objeto ao Controller que decide o que deve ser feito com o Objeto.

O Controller delega para um DAO persistir o Objeto ou como ActiveRecord o objeto se persiste.

A View tem como base o Objeto.

Essa e minha visao. :slight_smile:

Dado que todos os listeners são implementações de Observer e Action implementa ActionListener , então Action é uma implementação de Observer.

Então Action != Observer é falso, o que torna o resto da condição falsa.

Não obstante, Action tb não é um Command. Um comand é executado por outro objeto. Action não é executado, ele executa.

O objectivo de Action não é implementar o codigo executor e sim permitir dar um estado a esse código. É por isso que Action tem um setEnabled que quando ativado avisa todos os componentes que estão registrados no action através de um PropertyChangeEvent. Ou seja, Action é um mediador e pertence na camada controladora sim. Isto porque é fazendo setEnable no action que vc controla o estado do butões / menus / etc que estão acoplados ao Action e não fazendo setEnable() em cada um desses controles separadamente.

Resumindo, a visão do bzanchet está correta sim.
A única coisa nesta conversa é que nada disto tem a haver com MVC.
Tem a haver com MVP ou PresentationModel que é já algo que funciona em cima do Swing.

[quote=keller]A View cria um Objeto.

View passa o Objeto ao Controller que decide o que deve ser feito com o Objeto.

O Controller delega para um DAO persistir o Objeto ou como ActiveRecord o objeto se persiste.

A View tem como base o Objeto.

Essa e minha visao. :)[/quote]
Keller, beleza?

Você poderia elaborar um pouco mais, mostrar um exemplo resumidão pra eu entender melhor o que se passa no seu modelo?

Tipo, objeto deve ser algum de domínio, como usuário; view, um painel ou janela. E o controller? Tem um model aí?

Valeu!