Estrutura da Aplicação - MVC

Gostaria de saber a opinião da galera sobre a estrutura das classes da aplicação.

-Cidade _ Bean apenas com os atributos com gets e sets
int codigo;
String descricao;

Vou dar um exemplo:
-Tela de cadastro de cidade.
Esta tem uma instância de CidadeControll.

  • CidadeControll _ Tem os metodos para inserir/alterar, apagar e recuperar uma cidade. Caso alguma operação cause exceção ela tem a função de disparar um JOptionPanel

A Tela de Cadastro instancia o Bean Cidade e passa como parâmetro para por exemplo o método inserir para gravar no banco.

A CidadeControll por sua vez tem uma instância de CidadeDAO que implementa uma interface com os metodos para inserir/alterar, apagar e recuperar.

-CidadeDAO _ Pega uma connection e o parâmetro, no caso o objeto Cidade e grava no banco.

Ta ok… soh uma coisa: se a tua Control sempre for delegar direto pro DAO, voce poderia usar o DAO direto ( ao menos que a tua classe control decida para qual implementacao de dao delegar… ou seja, se ela for algo como / acessar um factory de dao’s )

Rafael

Olá,

O teu bean é um VO?

]['s

Seguinte, não mensionei mas essa arquitetura é pra usar EJB.

Estou amadurecendo a idéia e gostaria de receber sugestões !!!

Refatorei e está mais ou menos assim, citando um exemplo:

:arrow: Tela de venda (FM_Venda)

:arrow: RN_Venda
Possui uma instância de RN_Cliente e de RN_NotaFisal

:arrow: RN_Cliente
Possui uma instância de DAO_Cliente com os métodos insert, update, …, sendo que estes apenas invocam os metodos da DAO

:arrow: DAO_Cliente
Peja uma connection de uma classe especializada e executa os métodos insert, update, …

:arrow: RN_NotaFiscal
Possui uma instância de DAO_NotaFiscal com os métodos insert, update, …, sendo que estes apenas invocam os metodos da DAO

:arrow: DAO_NotaFiscal
Peja uma connection de uma classe especializada e executa os métodos insert, update, …

RN = Regra de Negócio

Ta legalzinho, mas… http://java.sun.com/docs/codeconv/ :wink:

FmVenda
RnVenda
RnCliente
DaoCliente
RnNotaFiscal
DaoNotaFiscal

e agora cv?

Tem alguma outra sugestão?

Bom, ja que a gente ta falando sobre nomenclatura… Rn e Fm nao fazem o menor sentido na primeira olhada… pq nao algo mais descritivo como Venda e VendaForm, ao inves de RnVenda e FmVenda? :smiley:

FormVenda
RegraNegocioVenda
RegraNegocioCliente
DaoCliente
RegraNegocioNotaFiscal
DaoNotaFiscal

RegraNegocio = Achei meio extenso.
DataAccessObject (Dao) = Acho que ficaria mais extenso ainda.

FormVenda ou VendaForm
DaoCliente ou ClienteDao

Peguei o espírito ou ainda tá meio confuso?

Olá,

RegraNegocio não precisa colocar.

ClienteForm
Cliente
ClienteDAO

]['s

fabgp2001, deixe-me ver se entendi:

ClienteForm - tranquilo
ClienteDAO - tranquilo

:arrow: Cliente - Este tem os atributos tipo: codigo, nome, endereço com os gets e sets.
Do jeito que vc está me sujerindo ele também teria os métodos insert, update, … que com uma instância de ClienteDAO faria a persistência.

É isso mesmo?

Nao necessariamente. O teu ClienteDAO poderia receber uma instancia de Cliente, ao inves do Cliente chamar o ClienteDAO.

Rafael

Pois é, mas era isso que eu estava fazendo.

Tenho por exemplo a Tela de cadastro de Cidade. Esta tem uma instância de RnCidade que controla as regras de negócio da cidade.
A regra de negócio da cidade é que tem uma instância de CidadeDAO onde faço a persistência.

A dúvida é a seguinte. Tenho uma classe chama Cidade somente com parâmetro e gets e sets. (Está classe está correta?)
Quanto pego os valores dos textfields da tela instâncio a Cidade (na tela mesmo) e passo para a RnCidade. Esta verá se esta tudo preenchido corretamente e repassará para a CidadeDAO fazer a persistência.
Ex.:

Cidade cidade = new Cidade(codigo, descricao);
RnCidade rnCidade = new RnCidade();
rnCidade.salvar(cidade);

Isso tudo na tela

A RnCidade recebe todos os erros que podem ocorrer quanto a persistência e validação, trata e repassa em forma de String para ser exibida na Tela em uma JOptionPane por exemplo.

Isso é um anemic domain model. Nao que seja ruim, por si só, mas pode ser melhor: http://www.martinfowler.com/bliki/AnemicDomainModel.html

Eu também tenho dúvidas a respeito da melhor estrutura para um modelo MVC… acho que a discussão fugiu um pouco do foco…

Então gostaria de retomar o assunto: qual seria a melhor estrutura MVC para o modelo proposto pelo Fabricio? É interessante ter uma classe de Negócio + uma classe Bean + uma classe DAO (considerando que poderíamos ter uma factory de DAOs)?

Olá cv

Estive lendo o artigo que você mencionou e pude identificar a presença de um Anemic Model no projeto em que trabalho.
Temos muitos EJBs (Session Beans) que tratam várias regras de negócio da aplicação. Alguns deles são inclusive statefulls.
Os objetos de domínio como (exemplo: Cliente, Produto, Venda, Pedido …) são planos e sem nenhuma codificação, exceto getters e setters.
A principal razão para isso é de que temos uma interface gráfica Swing que acessa esses Session Beans no servidor de aplicação (JBoss nesse caso). Isso implica na serialização de todos esses objetos de domínio, a fim de transportá-los pela rede até a máquina cliente, e portanto, quanto mais enxutos eles forem, mais rápido é o transporte.
Outro aspécto importante, é que várias regras de negócio da aplicação em questão (e algumas validações) precisam ser forçadas na própria interface, para torna-la altamente interativa. Para resolver isso, acabamos implementando várias classes que consideramos “modelos” no lado cliente. Esses modelos são geralmente implementados no estilo MVC, para exibir os dados em uma enorme variedade de formulários e controles visuais Swing extremamente complexos.

Para tornar meu relato ainda mais claro, darei alguns exemplos da interatividade que sempre buscamos:

Suponha que você tenha um formulário de entrada de dados para um objeto que representa uma “venda” no sistema. O usuário terá que associar à essa venda um objeto “cliente” já existente e também um objeto “pedido”,
Agora imagine que o esse objeto “pedido” possui uma coleção de “itens”, que representam todos os itens solicitados pelo “cliente”.
Imagine também, que o objeto “venda” também possui uma coleção de “itens” que representa todos os itens que foram realmente vendidos ao cliente, e para os quais foi emitida uma nota fiscal por exemplo.
Para criar, tal formulário tivemos que desenvolver uma classe que chamamos de “Lookup”. Essa classe se encarrega de criar uma janela modal na qual é exibida uma lista dos objetos que se deseja vincular. Por exemplo, uma lista de todos os clientes ou pedidos do sistema, que pode ser filtrada de acordo com alguns valores que podem ser informados pelo usuário nessa mesma janela. Para conseguir isso, a classe “Lookup” tem que recorrer ao servidor de aplicação para executar métodos de busca e obter as listas de objetos para exibição.
Suponha então, que ao associar um objeto “pedido” localizado através de um “Lookup” como mencionei antes, você tenha que criar automaticamente “itens” correspondentes na venda, pré supondo que todos os itens do pedido tenham sido efetivamente vendidos.
Levando em consideração que esses “itens” de venda devem ser exibidos em uma grade (JTable) tivemos que desenvolver um TableModel adequado para esse fim. Nesse caso, tal TableModel precisa acessar diretamente o objeto “venda” que estiver sendo editado para apresentar seus itens. Foi necessário ainda criar métodos auxiliares nesse TableModel para que se pudessem incluir, remover e alterar itens da lista dinamicamente, já que o usuário poderá querer incluir, remover ou alterar itens da venda antes de finalizá-la. Esses métodos, além de providenciarem a atualização do JTable também alteram a lista de itens do objeto “venda”.
Outra sofisticação comum, seria por exemplo, mandar um aparâmetro para o “Lookup” dos pedidos de forma que ele só pudesse exibir “pedidos” do “cliente” previamente informado. Ou no “Lookup” de “clientes” só poderiam ser exibidos os clientes que tivessem algum pedido que ainda não tivesse sido associado a nenhuma venda!
Na inclusão de novos itens na venda por exemplo, poderia ser necessiário verificar a dispobilidade de estoque da quantidade vendida, antes de permitir a inclusão do item no formulário.
Por fim a venda poderia ser enviada para o método “insert” de um Session Bean no servidor de aplicação que faria sua persistência e atualizaria o estoque debitando as quantidades dos itens vendidos.

(Agora imagine, que esse exemplo é bem mais simples do que o que realmente temos que implementar no sistema real…)

Se anlisarmos esse requisitos em um estilo mais OO e mais abstrato, poderiamos chegar a algumas conclusões mais lógicas em relação ao domínio de objetos, que com certeza seria mais “rico”.

  • A lógica de validação do pedido e do cliente poderia estar dentro dos respectivos métodos set na classe da venda. Ou poderia haver um método set para associar os 2 ao mesmo tempo.
  • A lógica de “copia” dos itens do pedido para a venda poderia também estar encapsulada dentro de um método set para o pedido dentro da classe venda. Ou poderia haver um método na classe venda específico para esse fim.
  • A validação do item da venda em relação ao estoque poderia ser feita no método addItem (que inclui um item na venda) ou então no método que associasse o pedido.
  • Para efetuar as baixas no estoque poderia também haver um método na própria classe da venda, ou poderia ser feito em Session Bean mesmo.

Entretanto, essa abordagem traria os seguintes problemas …

  • Teriamos objetos do domínio acessando Session Beans para buscar/validar informações e isso parece muito estranho.
  • Teriamos bastante código nas classes do domínio, aumentando bastante o seu custo de transporte pela rede.
  • A interatividade do formulário com o usuário seria perdida ou sua implementação se tornaria ainda mais complexa do que já é.

Para concluir …

Gostaria de perguntar se você vê alguma maneira de tornar esse modelo, menos “anêmico”, ou se você consegue identificar alguma falha de design em algum desses raciocínios…

E caso esse exemplo inspire mais alguém que também desenvolva uma interface Swing para uma aplicação J2EE, comentários serão bem vindos.

Saudações,
Gabriel C. Oliveira

Opa! Valeu pela otima explicacao, Gabriel! :smiley:

Um modelo de domínio rico tem algumas vantagens, e a primeira e mais importante de todas é que vc consegue representar, de forma realmente OO, os requisitos do seu sistema, e as funcionalidades dos seus objetos. Se voce parar pra pensar bem, um modelo de objetos anemico (feito de VOs, como no seu caso) é programação procedural, e um objeto que só tem getters e setters não é muito diferente de uma struct em C :frowning:

Pode ser, o importante aqui não é em que método colocar, mas sim que a lógica de negócio de um determinado objeto esteja contida nele, mesmo que através de delegação. Delegacao, alias, faz com que a gente ganhe o melhor dos dois mundos. É possivel, por exemplo, usar o Command Pattern, aliado a Decorators, e se divertir bastante:

[code]public class Cliente … {

public void addPedido(Pedido p) {
new CommandExecutor(new AddPedido(this, p)).execute();
}

}[/code]

[code]public class AddPedido … {

public AddPedido(Cliente c, Pedido p) {
this.cliente = c;
this.pedido = p;
}

public void execute() {
// …
// checa todas as regras, joga excecoes, etc
// …

c.getPedidos().add(p);
p.setCliente(c);

}

}[/code]

Dentro do CommandExecuter, voce pode se divertir decorando o command com transacoes, configuracoes extras, etc e tal. Mas quem tá de fora, ou seja, sua interface, não fica nem sabendo sobre o que está debaixo dos panos. O importante aqui é isolar os problemas. Persistência, distribuição e esse tipo de coisa podem ser isolados dentro do seu modelo de objetos, sem que a interface fique se preocupando muito com isso. O que tem de tão horrível em chamar um monte de setXXX() e addXXX() em um objeto de negocio, e quando terminar de trabalhar chamar um save()? :wink:

Agora, quanto aos “contras” de se ter um modelo de objetos rico:

Nao necessariamente. Como eu expliquei acima, os objetos do seu dominio so precisam servir de fachada pra um monte de outras esquisitices por baixo. E, dessas esquisitices, ninguem mais precisa ficar sabendo alem dos seus objetos de negocio :wink:

A quantidade de codigo nao aumenta o custo de transporte. A quantidade de dados, sim. Lembre-se que a serializacao não transporta o codigo toda vez que vc serializa um objeto, mas só o estado daquele objeto.

Não senhor, e alias muito pelo contrario. Eh possivel fazer TableModels mais inteligentes quando vc trabalha com objetos mais “completos”. Uma JTable que representa os Itens de um Pedido pode ser um Observer do Pedido, e adicionar um novo item ao pedido modifica a JTable, e nao o contrario (modificar a JTable causa uma alteracao no Pedido). Mais facil, mais OO, e com certeza usando menos codigo :smiley:

Cara, adorei essa thread!

Eu tb nunca tinha lido sobre o modelo anêmico, e percebi que grande parte das coisas que eu tenho desenvolvido sofre um pouco desse mal.

Geralmente a gente fala de separação de interesses (Separation of Concerns, até hoje não achei uma tradução definitiva pra isso) e acaba separando dado do código.

Pois eh, olha como já tá na cabeça que os objetos de domínio são por natureza passivos…

Eu acho que o vício (bom, hoje, e nesse contexto, parece um vício, quem sabe em alguns anos volta a ser moda) surge em parte pela grande quantidade de material que a gente lê e que é feita pensando num ambiente web, com HTTP, etc. Quase todos os meus value objects são pensados pra mapear valores que vêm de um POST, ou que vão ser exibidos numa página. Esses caras não têm nenhum motivo pra implementar regras de negócio.

Na verdade, escrevi tudo isso pra fazer essa pergunta: esses objetos devem e serão sempre value objects? Alguém já implementou algo diferente?

[]s!

Eu lembro de ter usado o bom, velho e infame HashMap no lugar dos objetos POSTados, sem muito problema. Eu tinha quase uma centena de forms ridiculamente diferentes pra mapear, e criar classes pra tudo isso (mesmo que fossem Actions do Struts/WebWork/Spring/SeuFrameworkFavorito) ia ser uma trabalheira proibitiva :smiley:

Depois que eu tinha os dados num Map, copiar eles pros lugares certos era relativamente tranquilo (os objetos de negocio recebiam o Map no construtor e se populavam). :wink:

Vamos ver se entendi.
Então os VOs deixariam de ter apenas os gettes e setters e passariam a ter todos os métodos de alteração do estado do objeto.

O que aconteceria com a minha classe com regras de negócio ou business object?