Modelo Anêmico é realmente ruim?

[quote=rogelgarcia]Acho que tá havendo um mal entendido aqui…

No post do sergiotaborda é dito que os objetos fantoche… como a classe Endereco que citei… sao apenas isso fantoche… e que isso é o correto… porque a responsabilidade delas é apenas ser repositorio de dados

Aí os defensores do modelo rico… dizem que as classes nao podem ser só fantoches… que devemos evitar o modelo anemico…

E o sergiotaborda como outros são contra o modelo anemico…

O que voces chamam de modelo anemico???
[/quote]

Acho que você não entendeu direito.

O modelo anêmico é quando você separa a lógica e as propriedades de uma entidade em classes diferentes.
Porque? Porque o conceito de objeto é propriedades + funcionalidades, sendo assim separar isso em duas classes vai contra o conceito de orientação a objeto.

O que o sergio defende é de que se o objeto não tem nenhuma funcionalidade (regra de negócio), você não precisa inserir alguma só para dizer que tem.

E se um objeto só tem o proposito de armazenar dados que assim seja, isso não torna o modelo anêmico.

Entendeu?

O que é VO?

Sim… entendi isso… e é o que eu defendo tb…

Só que o que eu tinha como conceito de modelo anemico… é objetos com apenas getters e setters…
Os objetos com getters e setters… são os objetos que o sergio defente…

VO Value Object… é a entidade por exemplo… a classe Endereco

[quote=Frango]
O que o sergio defende é de que se o objeto não tem nenhuma funcionalidade (regra de negócio), você não precisa inserir alguma só para dizer que tem.

E se um objeto só tem o proposito de armazenar dados que assim seja, isso não torna o modelo anêmico.

Entendeu?[/quote]

Independente de ser modelo anemico ou nao, se um objeto não tem funcionalidade (ou seja, não troca mensagens com outros objetos), qual motivo da sua existencia? Pra mim isso não é um bom sinal de design OO.

[quote=mochuara][quote=Frango]
O que o sergio defende é de que se o objeto não tem nenhuma funcionalidade (regra de negócio), você não precisa inserir alguma só para dizer que tem.

E se um objeto só tem o proposito de armazenar dados que assim seja, isso não torna o modelo anêmico.

Entendeu?[/quote]

Independente de ser modelo anemico ou nao, se um objeto não tem funcionalidade (ou seja, não troca mensagens com outros objetos), qual motivo da sua existencia? Pra mim isso não é um bom sinal de design OO.[/quote]

Ele existe para guardar dados…
na classe Endereco… rua cep bairro … etc

Andei pesquisando aqui na internet e achei alguns posts sobre o Anemic Domain Model, para ver se eu entendia realmente o que queria dizer…

Esse artigo mostra modelos de código
http://vitamic.wordpress.com/2007/01/04/anemic-domain-model-illustrated/

O que eu defendia, é que não há nada de errado em ter classes com apenas getters e setters… ou seja, do meu ponto de vista esse anemic model (classes só com getters e setters) não é um problema…

O sergio também concorda que pode haver esse tipo de objetos com apenas getters e setters (conforme artigo em seu blog)…

Agora os que não gostam do anemic model, querem colocar as funcionalidades no modelo, por exemplo o método salvar… como até dito no artigo do link que postei…

O que eu considero errado…

Temos então duas definições…

Anemic Model, é uma classe que deveria possuir funcionalidades (como getIdade() em PessoaFisica) mas essas funcionalidades estão em outra classe… OK Concordo que nesse caso o Anemic Model é ruim…

Tem gente que defende que o método salvar deve ficar no Modelo, alegando que é Anemic Model se o salvar ficar em outra classe… Não concordo… e por isso disse que anemic model não é ruim…

Então, uma classe com apenas getters e setters, é anemic model? Como por exemplo a classe Endereco, que nao tem que fazer mais nada, a não ser guardar as informacoes do endereço…

E os que defendem que o método salvar deve estar no modelo? Chamam modelos sem esse método de anemic model?

Considerando que há essa divergência entre os Anemic Models… eu acho que existem “níveis de anemia” e o que cada um considera anêmico varia nesses niveis…

(vou simplificar o código para ficar mais fácil entender… nao vou colocar os getters e setters tb nao)

Anemia 0 - Absolutamente nenhuma funcionalidade no Modelo…

class PessoaFisica {
      String nome;
      Date dataNascimento;
}

class PessoaFisicaBO {
      int getIdade(Pessoa p){...}
      boolean declarouIR(Pessoa p){
              ...
             // web service para acessar o site da receita federal
      }

}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 1 - Funcionalidades apenas pertinentes ao modelo (onde o modelo resolve por si só o problema)

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...} // MÉTODO NO MODELO
}

class PessoaFisicaBO {
      
      boolean declarouIR(Pessoa p){
              ...
             // web service para acessar o site da receita federal
      }
}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 2 - Funcionalidades apenas pertinentes ao modelo independente se precisa de outras informacoes, ou objetos…

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){ // MÉTODO NO MODELO
              ...
             // web service para acessar o site da receita federal
      }
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 3 - Funcionalidades pertinentes ao modelo mas independente de sua responsabilidade

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){
              ...
             // web service para acessar o site da receita federal
      }
      void save(){...}// MÉTODO NO MODELO
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 4 - Funcionalidades pertinentes ao modelo mas independente de sua responsabilidade (nível extremo, igual ao do framework do carinha)

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){
              ...
             // web service para acessar o site da receita federal
      }
      void save(){...}
      void processCrud(request) {...}// MÉTODO NO MODELO
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    
}

class PessoaFisicaAction {
     
}

Alguns vão dizer que o anemic model é o que é exemplificado em 0, 1, 2, 3 ou 4…

Varia de acordo com a interpretação… o que eu considerava que seria anemic model … seria o exemplo 0 ou 1…

No caso eu recomendaria fazer como no exemplo 1… Eu considero como anemic model (de acordo com o que eu já ouvi falar) … mas não acho ruim… considero ser a melhor opção…

Vemos que o excesso de zelo para se evitar o anemic model, pode piorar o modelo, trazendo para ele responsabilidades que não são pertinentes…

[quote=rogelgarcia]

Alguns vão dizer que o anemic model é o que é exemplificado em 0, 1, 2, 3 ou 4…

Varia de acordo com a interpretação… o que eu considerava que seria anemic model … seria o exemplo 0 ou 1…

No caso eu recomendaria fazer como no exemplo 1… Eu considero como anemic model (de acordo com o que eu já ouvi falar) … mas não acho ruim… considero ser a melhor opção…

Vemos que o excesso de zelo para se evitar o anemic model, pode piorar o modelo, trazendo para ele responsabilidades que não são pertinentes…[/quote]

eu tenho a mesma visão do roel

Uma dúvida que tenho… eh assim, no modelo ‘rico’, se eu quisesse re-utulizar meu domain model em outra aplicacao seria possivel? Pq tipo assim… eu tenho um projeto que estou desenvolvendo a algum tempo onde eu separei o dominio em um jar separado… esse jar pertence exclusivamente a minha empresa… nela eu tenho os mais variados tipos de classes, desde pessoa até coisas especificas de outros projetos… o que as diferencia é apenas o pacote… por exemplo… tenho com.teste.domain.Pessoa -> com.teste.model.PessoaFisica -> com.teste.cliente1.model.Cliente… como seria isso no modelo rico??

Outra coisa… se eu quiser mudar a camada de persistencia no modelo ‘rico’, simplesmente alterando o jar app_hibernate para app_jdbc da minha aplicação é possível???

Outra… se eu quiser re-utilizar meu jar de domain e meu jar de persistence ou model em outra aplicação é possível???

@dohko

Sinceramente, eu não tenho o sonho de reaproveitar componentes de domínio. Ai você pensa: “mas o dominio do aplicativo A se parece com o do aplicativo B”, talvez seja o caso de refatorar ambos aplicativos para A, B e C, com C contendo as partes comuns. Você pode até generalizar/abstrair os modelos do domínio, o resultado vai ser ou alguma coisa pouco útil ou um trambolho complexo com interfaces gigantes e não relacionadas ao dominio. Em todo caso vale a pena testar, a minha experiência diz que fazer isso não é bom, é mais prático reescrever.

Adicionando: dá uma olhada nesse link http://en.wikipedia.org/wiki/Subject-oriented_programming

Pergunta: com.teste.domain.Pessoa -> com.teste.model.PessoaFisica -> com.teste.cliente1.model.Cliente o que é isso? Herança? Esses “teste” no nome da classe são testes (ex. unitário) ou é só um exemplo de nome?

Como seria no modelo rico?
O que eu falei até aqui não diz respeito a modelo rico ou modelo anêmico, tanto faz.

[quote]Outra coisa… se eu quiser mudar a camada de persistencia no modelo ‘rico’, simplesmente alterando o jar app_hibernate para app_jdbc da minha aplicação é possível???
[/quote]

Sim, tanto no modelo rico quanto no modelo anêmico é possível utilizar abstrações e “camuflar” o que tem por baixo.

Pelo visto você anda tendo um bom reaproveitamento com os modelos anêmicos / semi-anêmicos / não anêmicos (ou outro). No que de fato consiste esse reaproveitamento? Importar um jar , subir um schema (de banco) e realizar uma série de testes automáticos?

[quote=rogelgarcia]Considerando que há essa divergência entre os Anemic Models… eu acho que existem “níveis de anemia” e o que cada um considera anêmico varia nesses niveis…

(vou simplificar o código para ficar mais fácil entender… nao vou colocar os getters e setters tb nao)

Anemia 0 - Absolutamente nenhuma funcionalidade no Modelo…

class PessoaFisica {
      String nome;
      Date dataNascimento;
}

class PessoaFisicaBO {
      int getIdade(Pessoa p){...}
      boolean declarouIR(Pessoa p){
              ...
             // web service para acessar o site da receita federal
      }

}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 1 - Funcionalidades apenas pertinentes ao modelo (onde o modelo resolve por si só o problema)

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...} // MÉTODO NO MODELO
}

class PessoaFisicaBO {
      
      boolean declarouIR(Pessoa p){
              ...
             // web service para acessar o site da receita federal
      }
}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 2 - Funcionalidades apenas pertinentes ao modelo independente se precisa de outras informacoes, ou objetos…

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){ // MÉTODO NO MODELO
              ...
             // web service para acessar o site da receita federal
      }
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    void save(PessoaFisica p){...}
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 3 - Funcionalidades pertinentes ao modelo mas independente de sua responsabilidade

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){
              ...
             // web service para acessar o site da receita federal
      }
      void save(){...}// MÉTODO NO MODELO
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    
}

class PessoaFisicaAction {
     void processCrud(request) {...}
}

Anemia 4 - Funcionalidades pertinentes ao modelo mas independente de sua responsabilidade (nível extremo, igual ao do framework do carinha)

class PessoaFisica {
      String nome;
      Date dataNascimento;
      int getIdade(){...}
      boolean declarouIR(){
              ...
             // web service para acessar o site da receita federal
      }
      void save(){...}
      void processCrud(request) {...}// MÉTODO NO MODELO
}

class PessoaFisicaBO {
      

}

class PessoaFisicaDAO {
    
}

class PessoaFisicaAction {
     
}

Alguns vão dizer que o anemic model é o que é exemplificado em 0, 1, 2, 3 ou 4…

Varia de acordo com a interpretação… o que eu considerava que seria anemic model … seria o exemplo 0 ou 1…

No caso eu recomendaria fazer como no exemplo 1… Eu considero como anemic model (de acordo com o que eu já ouvi falar) … mas não acho ruim… considero ser a melhor opção…

Vemos que o excesso de zelo para se evitar o anemic model, pode piorar o modelo, trazendo para ele responsabilidades que não são pertinentes…[/quote]

É por causa desse tipo de discussão inutil que estou de saco cheio de desenvolver em Java. Esse tipo de coisa simplesmente não existe em outras linguagens, e por isso elas são geralmente chamadas de mais produtivas.

É… dá pra ver que vc tá nervoso mesmo… heheheheh

Mas essa discussão é independente da linguagem…

[quote=rogelgarcia]É… dá pra ver que vc tá nervoso mesmo… heheheheh
[/quote]

Que nada, esse lance de anemia 0, anemia 1, anemia 2, foi até engraçado! :lol:

Eu ia colocar um com vitamina B12 pra ver se melhorava… ehhehe

http://guj.com.br/posts/list/30/203206.java#1029177

[quote=rogelgarcia]Considerando que há essa divergência entre os Anemic Models… eu acho que existem “níveis de anemia” e o que cada um considera anêmico varia nesses niveis…

(vou simplificar o código para ficar mais fácil entender… nao vou colocar os getters e setters tb nao)
[/quote]

Rogel, concordo com vc em partes, mas pra mim se a classe é somente uma estrutura de campos, ela deve ser imutavel, ou seja, vc não altera o estado dela, TODOS os campos vem no construtor, e vc possui somente getters para recuperar o valor.

[quote=faq]@dohko

Adicionando: dá uma olhada nesse link http://en.wikipedia.org/wiki/Subject-oriented_programming

Pergunta: com.teste.domain.Pessoa -> com.teste.model.PessoaFisica -> com.teste.cliente1.model.Cliente o que é isso? Herança? Esses “teste” no nome da classe são testes (ex. unitário) ou é só um exemplo de nome?

[/quote]

so o nome, com.minhaemprsa.domain.Pessoa -> com.minhaempresa.model.PessoaFisica -> com.minhaempresa.meucliente.model.Cliente

Na verdade a questão não é só reaproveitar, alem de manter um certo padrao em todas as bases, estou tentando criar uma dependencia do modelo do cliente com o meu

[quote]
Pelo visto você anda tendo um bom reaproveitamento com os modelos anêmicos / semi-anêmicos / não anêmicos (ou outro). No que de fato consiste esse reaproveitamento? Importar um jar , subir um schema (de banco) e realizar uma série de testes automáticos?[/quote]

Um exemplo seria se eu quisesse usar o meu model, domain e persistence em uma aplicacao desktop… seria apenas importar os jars

Mas uma dúvida que ainda tenho, como fica a persistência desses objetos? Eu posso ter um DAO como propriedade da entidade ou eu tenho que instanciar o DAO dentro dos meus métodos apenas quando eu precisar usa-los?

Alguém pode exemplificar como fica a persistência em um modelo rico?

[quote=rogelgarcia](definidas no GOF) para boas práticas de OO:

2 - Programar para interfaces e não para implementações

Se voce pensar na interface de PessoaFisica, o que é uma pessoa física? O que ela tem? O que ela pode fazer? Faz parte da pessoa física se salvar? Você se salva? Se carrega?

Se voce faz um programa chamando pessoaFisica.save(), voce começa a programar para a implementação, pois a interface que define uma pessoa física, não tem isso de salvar…

[/quote]

E mais… na verdade não é só o GOF quem diz isso… basta pensar no principio da abstração…

em um artigo que estou trabalhando, fiz a seguinte citação:

[quote=Andre Brito][quote=mochuara][quote=rogelgarcia]Para mim, o modelo anemico é completamente válido…

Exemplo, suponhamos uma classe Endereco.

Nessa classe temos os atributos, rua, cep, bairro, etc.

A classe Endereco nada mais é do que um tipo de dados complexo. Ou seja, não tem que fazer nada mesmo, a nao ser, guardar as informacoes.

[/quote]

Essa não é a definição de modelo anêmico. Modelo anemico é quando, havendo algum comportamento, ele é colocado em um objeto diferente daquele que possui os dados. O que vai contra aos principios da OO que é agrupar os dois no mesmo objeto.[/quote]
Faço das suas as minhas palavras.
Aliás, acho que colocar o validaCep() em uma outra classe é errado… Não errado, mas eu não gostaria de fazer dessa maneira. É a mesma coisa que colocar calcularIdade() de um objeto do tipo Pessoa dentro de uma outra classe… Vira aquela coisa de gets e sets pra tudo quanto é lado (lembrem-se dos artigos de que getters e setters ‘are evil’). [/quote]

getters and setter are not evil, people just dont’t understand them…