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!