Como expor Objetos de Negócio sem uso de TO

Já muitas discuções a respeito sobre Domain Model, ADM e outras mais neste forum e os links do shoes.

Mas continuo com uma dúvida sutil.

Após ter modelo o domínio como devo expor somente os valores dos objetos de negócio tendo em vista que minha camada de apresentação é Swing, e minha camada de aplicação é Webservice.

Ex. Tenho um objeto Reserva, que contém métodos de criar, alterar e remover, mas estes métodos só podem ser utilizados na camada de negócio pois tem uma série de validações a serem feitas, mas não por este objeto e sim por um Gerenciador de Reservas.

Obs: não gostaria de contratar um “consultor” para resolver este problema.

Coloque seu webservices como fachada recebendo e retornando instancias de Reserva ue.

Pode ser que no caso do framework de WS que você use, não seja possivel fazer diretamente binding para o teu objeto de domínio, nesse caso você vai precisar de assemblers em ambas as pontas da aplicação.

[quote=ptrecenti]Já muitas discuções a respeito sobre Domain Model, ADM e outras mais neste forum e os links do shoes.

Mas continuo com uma dúvida sutil.

Após ter modelo o domínio como devo expor somente os valores dos objetos de negócio tendo em vista que minha camada de apresentação é Swing, e minha camada de aplicação é Webservice.

Ex. Tenho um objeto Reserva, que contém métodos de criar, alterar e remover, mas estes métodos só podem ser utilizados na camada de negócio pois tem uma série de validações a serem feitas, mas não por este objeto e sim por um Gerenciador de Reservas.

[/quote]

  1. Os métodos criar/remover/alterar estão na classe Reserva ou na classe GerenciadorDeReserva ?
    Se estiverem na reserva, então essa classe não é uma verdadeira classe de dominio é um DAO. Solução: faça um refactoring de Reserva para ReservaDAO e crie um objeto Reserva que seja realmente de dominio.
    Use esses objetos como TO, faça todos os objetos do domínio serem serializable se necessário. (ver nota)
    Se estiverem no gerenciador, otimo, Reserva já é um objeto de dominio. Use ele mesmo como TO (ver nota)

2)Os métodos de dominio só podem correr no servidor ?
Se não, sem problema. Se sim … ver nota

Como o seu sistema já usa uma arquitetura de serviços , então o mais lógico é usar os objetos de domínio apenas no servidor. Suponho que seja isto que está fazendo. Só que esta abordagem implica em que os dados têm que viajar do cliente ao servidor e de volta, sendo impossivel usar os objetos de domínio como TO e forçando a criação de TO além dos objectos de dominio, criando uma duplicação de estado.
As alternativas são pois:
A) Usar um dominio single-tier (que corre num único andar) que corre apenas no servidor, e um conjunto de Serviços , TO e BusinessDelegates (objeto que ficam no cliente e respondem a pedidos do cliente comunicando com o servidor usado os TO e os serviços).
B) Criar um dominio cross-tier (que corre em qualquer andar) que use proxies por baixo dos panos. Esses proxies usariam os webservices.
Este modelo é simples de criar com IoC, implica em criar Proxies, mas não implica em usar TO.

B não é um AMD e, segundo este forum, A também não. Então sinta-se à vontade para escolher o mais simples para o seu caso, que pela sua descrição é A.

Ok, na verdade minha dúvida é vou ter que colocar estes objetos de negócio lá no meu cliente, mas não posso colocar todo o lib de negócio, só vou precisar de alguns objetos como o Reserva e o Sala.
A não ser que eu crie stubs mas só ouvir esta palavra me dá arrepios.
Seria melhor criar uma interface para estes objetos e implementa-los de forma diferentes quando estiver no cliente e servidor?

[quote] 1) Os métodos criar/remover/alterar estão na classe Reserva ou na classe GerenciadorDeReserva ?
Se estiverem na reserva, então essa classe não é uma verdadeira classe de dominio é um DAO. Solução: faça um refactoring de Reserva para ReservaDAO e crie um objeto Reserva que seja realmente de dominio.
Use esses objetos como TO, faça todos os objetos do domínio serem serializable se necessário. (ver nota)
Se estiverem no gerenciador, otimo, Reserva já é um objeto de dominio. Use ele mesmo como TO (ver nota) [/quote]

O objeto Reserva não é um DAO só coloquei estes nomes para não usar get/set para cada um de seus atributos.

Na verdade o objeto reserva não é um Objeto real ele representa um estado do Objeto Sala, minha sala tem métodos registrarReserva e RemoverReserva. Este Objeto só se tornou objeto pois ele tem atributos em particular relacionados a uma reserva como: Equipamentos que serão utilizados, Usuario que criou a reserva e qual o Motivo da Reserva.

[quote] B) Criar um dominio cross-tier (que corre em qualquer andar) que use proxies por baixo dos panos. Esses proxies usariam os webservices.
Este modelo é simples de criar com IoC, implica em criar Proxies, mas não implica em usar TO.[/quote]

Acredito que esta seja uma boa solução a pergunta que ecoa agora é:
Criar interfaces destes objetos colocar todas as interfaces em uma distribuição chamada ex: “negocio-api” e injetar a implementação no tier de Apresentação, Aplicação, Negócio e Integração?
E isso mesmo? Alguém já fez isso?

[quote=ptrecenti]
Seria melhor criar uma interface para estes objetos e implementa-los de forma diferentes quando estiver no cliente e servidor?[/quote]

Essa é a pergunta que eu também gostaria de ver respondida.

Acho que a resposta depende de se os objetos têm um comportamento diferente quando estão no cliente de quando estão no servidor. Se não têm, não é necessária uma forma diferente. A pergunta é: têm ? se sim, dê exemplos para a gente visualizar melhor uma solução.

[quote=ptrecenti][quote] B) Criar um dominio cross-tier (que corre em qualquer andar) que use proxies por baixo dos panos. Esses proxies usariam os webservices.
Este modelo é simples de criar com IoC, implica em criar Proxies, mas não implica em usar TO.[/quote]

Acredito que esta seja uma boa solução a pergunta que ecoa agora é:
Criar interfaces destes objetos e injetar a implementação no tier de Apresentação e Aplicação?[/quote]

Sim. É essa a ideia

A difiereça é a conexão remota, se eu estiver no cliente preciso enviar uma mensagem para o servidor.

A difiereça é a conexão remota, se eu estiver no cliente preciso enviar uma mensagem para o servidor.[/quote]

Sim. Mas isso é meio abstrato demais. enviar mensagem pode ser desde invocar um método até JMS passando por webservice. Que tipo de mensagem?

Aí vai minha opnião:

Como o Paulo disse, ele tem bem definido o Domain Model.
A questão é: Como eu sei se esse DM é anêmico ou não ? Devo ou não utilizar TO ?

Segundo Martin Folwer o principal sintôma de ADM é a utlizição de objetos(sem sentido algum no meu modelo, por exemplo, objetos de valores que não expressão nenhum comportamento) com um relacionamentos forte entre eles.

“The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is very little behavior on these objects. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects which capture all the domain logic. These services live on top of the domain model and use the domain model for data.”

Num primeiro momento eu generalizei tudo, achei que não era mais pra utilizar os VO´s, TO´s e DTO´s, EJB´s e que todos os meu modelos de projetos eram anêmicos.
Mas, refletindo um pouco, percebi que ele estava se referenciando SOMENTE ao modelo de negócio e não a integração entre as camandas.

Pois bem, agora como eu expor um serviço que o Domain Model possa prestar é uma outra questão(“Devo ou não utilizar TO ?”) que não tem relação alguma com com o anti-pattern ADM. Uma única opinão que o Martin expressou referente à EJB foi essa:

“I don’t know why this anti-pattern is so common. I suspect it’s due to many people who haven’t really worked with a proper domain model, particularly if they come from a data background. Some technologies encourage it; such as J2EE’s Entity Beans which is one of the reasons I prefer POJO domain models.”

NOTE que ele disse que prefere utilizar classes POJO´s ao invés de deixar todas as responsabilidades para os Entity Beans.

Então Paulo, acho que a preocupação que você tem é a mesma que tenho. Mas acredito que a idéia é essa :

Se você quer expor serviços que o seu modelo de domínio possa prestar para um cliente e se a plataforma deles forem homogeneas(JAVA/JAVA), vc pode sim utilizar(um EJB Session Bean com um método retornando um TO) e a SUN diz que é uma boa prática NESTE E SOMENTE NESTE CASO. Agora se as plataformas forem heterogeneas, vc deve partir para utilização de Web Services.

Enfim, essa é minha opinião a respeito. Fiquem à vontade para sugestões, críticas, etc.

Abração à todos.

Você colocou bem o problema. É esse “somente” que não é verdade com clientes remotos. O modelo de negócios é uma camada especial. Tudo bem. Mas camada (separação lógica) é diferente de andar (separação fisica)

Imagine um sistema simples de banco com a classe Conta
Num modelo de dominio rico vc faria

Conta contaA =Contas.findByID(10);

if (contaA.temCredito()){
   // pinta o nome de azul
} else {
 // pinta de vermelho

}

O método temCredito de Conta é um método de negócios para avaliar uma série de coisas. Entre elas - isto é só um exemplo - ele usa um serviço de protecção ao credito do ppr banco mas que fica noutra máquina e é acessado via webservice. Este serviço , devido a questões de segurança, só pode ser acessado do servidor de aplicação e nunca do cliente swing.

Bom, então se executarmos aquele codigo no servidor, tudo blz.
Mas se executarmos no cliente ele não vai funcionar. Mas é no cliente que ele é necessário porque o seu objetivo é possibilitar que o operador faça decisões com proeficiencia baseado em dicas visuais. Esse é ponto de ter uma UI rica.

Seria interessante se a camada lógica de negocio estivesse disponível no cliente, porque existem regras simples que podem ser executadas lá. Nada melhor que ter as regras à mão.

Mas ao fazer isto estarei tb disponabilizando métodos que não podem ser executados corretamente a partir do cliente. Este é o problema. A distribuição física da camada lógica. A integração de camadas não tem nada a ver com a distribuição fisica, excepto que teremos que colocar uma camada de transporte (RMI, Webservice, EJB , etc) e é ai que estamos tentado saber qual camada de transporte não necessita de TO.

Agora pense que a camada de negocio está apenas no servidor.
O que se faz, como vc falou , é usar TO. Eu teria um ContaTO e um serviço ValidaCredito que eu chamaria mais ou menos assim :

ValidaCredito serviço = ..//obtem serviço
serviço.temCredito(ContaTO conta)

Ah! , mas agora eu tenho uma Conta e um ContaTO e mais um Serviço no meio. Então o que me impede de implementar o Serviço assim :


public boolean temCredito(ContaTO conta){

   // chama serviço remoto de proteção ao credito
   ServicoPC servico = ... // obetem serviço
   return servico.temCredito(conta);

}

em vez de assim:


public boolean temCredito(ContaTO conta){

   // chama objeto do dominio
   Conta conta = ContaAssembler.assemble(conta);
   return conta.temCredito();
}

Nada! Então nada me impede de tornar o sistema anémico.
Além disso no cliente não tenho acesso a Conta, apenas a ContaTO e tudo o que eu tiver que fazer no cliente com “contas” terei que fazer com ContaTO que é um objeto sem comportamento. Ah,mas isso é anemic domain model no cliente . Não importa que no servidor tenha um modelo de dominio bonitinho , rico e bem feito, se no cliente não o posso usar e tenho que usar um ContaTO para fazer as vezes do Conta.

Ora, é esta pegadinha do sistema distribuído que seria bom evitar. Isso implica em:

  1. Não existir nenhum TO. Apenas objectos do dominio com dados e comportamento. Eles mesmos trafegariam pelos menos pareceriam ser trafegados.
  2. Não usar serviços no cliente. Pois isso é uma forma de driblar o uso de objetos do domínio.
  3. Os objetos de domínio têm que ser cross-tier (funcionar em qualquer tier)

Tem sim. Repare que no momento que vc decide que seus objectos de domínio não sairão do servidor, então a informação tem que ser transferida de outra forma, e automáticamente entram os TO. Mesmo que sejam coisas como arquivos XML, não deixam de ser TO (são TO serializados)
Vc tem que se lembrar que os entity beans são remotos e portanto são um domain model cross-tier por natureza (EJB 1.1). Mas isso mostrou-se enificiente e por isso os Entity Beans foram localizados (interface local foi adicionada ao padrão e recomendada) e depois viraram até POJO. Mas isso a custo de usar Stateless Beans para fazerem o transporte e portanto deixando de ter um modelo cross-tier e automáticamente tento a necessidade de TO.
Claro que pode ser argumentado que o TO não precisa carregar todos os campos que o objecto de dominio tem. Certo. Mas nesse caso teremos um TO para cada objecto de dominio e para cada serviço diferente. Tb não ajuda.

Pois é. Mas essa afirmação não é de agora. É do tempo do EJB 1.1. O que ele quiz dizer é que não quer ter um mecanismo de domínio remoto que onera o sistema em demasia e prefere POJO proque é simples.

Em termos de transporte não temos muitas opções,ou é EJB/RMI ou WebService/HTTP. Isso é um dado assente e pacifico.
Num sistema complexo vc não quer ter que lidar com a camada de transporte a toda a hora. ( A bem dizer isso deveria até ser injetado e passivel de modificar a qq hora. )

O ponto está em fazer com que os objetos de dominio existam e possam ser usados fora do servidor da mesma maneira que seriam usado dentro dele. Sem usar TO em lugar algum.
A razão para essa necessidade é:

  1. O cliente precisa usar regras de negocio para renderizar uma interface mais amigável ou produzir alguma informação (mensagens de validação por exemplo) que ajuda a evitar cliques e espera.
  2. Fazer 1 evitando o ADM no cliente ( é pacifico que no servidor não temos problemas em evitar o ADM)
    3)Eliminar o uso de TO por completo pois são na realidade duplicados dos objetos de domínio , mas sem comportamento. O TO obriga inevitávelemtne a usar o padrão Service portanto multipliando por 2 , no minimo, o numero de classes.

Sabe-se que o modelo com TO e serviços funciona, o ponto é sair desse modelo e levar para o cliente a mesma simplicidade do dominio do servidor. Não sei se isso ficou claro pelas mensagens anteriores.

Bem levantado. E quando se leva o objeto de domínio para o cliente temos outro problema: segurança. Existem métodos que só podem ser usados no servidor e outros só no cliente.

OK até agora só dúvidas, e mais dúvidas não é uma questão simples de se tratar.
IMHO partindo do princípio que temos no servidor as camadas de aplicação, negócio e integração, a idéia seria expor na camada de aplicação brokers que estimulam a camada de negócio e na camada de apresentação simplesmente utilizaria os serviços expostos pela aplicação e cria os objetos que facilitassem o uso dos serviços expostos da camada de aplicação, basicamente seria a criação dos strubs, não tem outra forma, ou tem?

[quote=ptrecenti]OK até agora só dúvidas, e mais dúvidas não é uma questão simples de se tratar.
IMHO partindo do princípio que temos no servidor as camadas de aplicação, negócio e integração, a idéia seria expor na camada de aplicação brokers que estimulam a camada de negócio e na camada de apresentação simplesmente utilizaria os serviços expostos pela aplicação e cria os objetos que facilitassem o uso dos serviços expostos da camada de aplicação, basicamente seria a criação dos strubs, não tem outra forma, ou tem?[/quote]

Acho que não.A questão seria como criar esses strubs/proxies. Partindo da ideia de usar IoC, ou algum método de fabrica, seria simples. Para os casos mais simples cria duas classes é suficiente. Para o caso extremo poderiamos recorrer a AOP em particular a ferramentas como o Spring AOP.

opa galera
desculpa fugir um pouco da discussão de alto nível aí, mas como minha dúvida é sobre TO´s resolvi aproveitar o tópico

eu tenho uma aplicação em que tenho 2 classes de negócio: Permissão e Horário
uma Permissão pode ter vários Horários, e cada Horário pode ter apenas 1 Permissão
assim, no meu construtor de Horario eu passo uma Permissao:

public Horario(Permissao permissao) {
   this.permissao = permissao
}

e eu preciso passar a lista de horários de uma determinada Permissao para minha jsp
só que minha classe Horario nao tem um construtor vazio, e meu framework exige um construtor vazio para iterar a coleção de Horarios, assim como getters e setters para todas as propriedades
qual a maneira correta de resolver este problema?
a única maneira que eu estou visualizando é criar uma classe HorarioTO que recebe todas as propriedades de Horario, e enviar esta classe HorarioTO para a página
esta é uma solução correta?

[quote=SadNess]opa galera
desculpa fugir um pouco da discussão de alto nível aí, mas como minha dúvida é sobre TO´s resolvi aproveitar o tópico

eu tenho uma aplicação em que tenho 2 classes de negócio: Permissão e Horário
uma Permissão pode ter vários Horários, e cada Horário pode ter apenas 1 Permissão
assim, no meu construtor de Horario eu passo uma Permissao:

public Horario(Permissao permissao) {
   this.permissao = permissao
}

e eu preciso passar a lista de horários de uma determinada Permissao para minha jsp
só que minha classe Horario nao tem um construtor vazio, e meu framework exige um construtor vazio para iterar a coleção de Horarios, assim como getters e setters para todas as propriedades
qual a maneira correta de resolver este problema?
a única maneira que eu estou visualizando é criar uma classe HorarioTO que recebe todas as propriedades de Horario, e enviar esta classe HorarioTO para a página
esta é uma solução correta?[/quote]

Não. A forma melhor seria não usar o construtor publico e sim um método set protegido

public Horario{
  
  public Horario()  {

  }
  protected void setPermissao(Permissao permissao){
          this.permissao = permissao
  }
}

Repare que você está criando uma relação em que o horário é obrigado a ter uma permissão. Então o horário depende de permissão. Ai a melhor forma é deixar que permissão crie o objeto ou pelo menos injete a sua dependência assim :


public class Permissao {

    public void addHorario(Horario horario){
           horarios.add(horario);
           horario.setPermissao(this);
    }

}

e por isso o método é protected

certo
entendi

mas vamos supor que por algum motivo minha classe Horario não pudesse ter um construtor vazio

qual seria a solução para enviar os dados para a página?

[quote=SadNess]certo
entendi

mas vamos supor que por algum motivo minha classe Horario não pudesse ter um construtor vazio

qual seria a solução para enviar os dados para a página?[/quote]

Acho que é melhor abrir um outro topico explicando direitinho o seu problema. Se colocar as classes ainda melhor.