Depois que o cv me instigou a ler mais sobre o assunto, encontrei o seguinte artigo, que deveria ter lido tempos atrás:
Nele, entre outras coisas, o autor afirma o seguinte:
Sendo assim, DAO não seria uma anti-pattern? Operações CRUD deveriam então ser realizadas dentro das próprias classes? Ou não?
E analisando a evolução do código do autor, percebi o uso de getters e setters pode ser arriscado, então deve-se pensar algumas vezes e escrever o código com cuidado.
Porém, ao usar frameworks como Hibernate, que provê muitas facilidades, o desenvolvedor é obrigado a definir getters/setters para todos os atributos a serem persistidos. E então? Usar ou não usar essas facilidades?
Colocar getters e setters pra satisfazer o framework nao te impede (bom, nao totalmente) de continuar com o encapsulamento bom - voce pode colocar as operacoes que lidam com aqueles dados na mesma classe mesmo assim.
Mas cv, sobre o link que você me passou, bem … como implementar isso de forma coerente?
class Pessoa() implements HibernateSessionAware
{
// ...
public void save()
{
session.save( this );
}
}
Isso?
E como colocaria várias operações dentro de uma transação fazendo desta maneira? E se o meu domínio tem centenas de objetos, não fica meio complicado para manter essas classes que implementam ActiveRecord?
Obrigado cv
ps.: fala pro sr Flower aumentar o tamanho do texto do site dele :mrgreen:
Nesse último ele argumenta que MVC não é OO. Eu acho que ele se apega demais ao encapsulamento. É uma diretriz, não uma lei. De qq forma é uma boa leitura.
Eh preciso saber absorver o conteudo de muitos desses artigos. Alguem pode ler e tomar atitudes “drasticas” se confiar cegamente no que o autor diz, aumentando a “complexidade da aplicacao” (ou qualquer outra coisa, nao vem mto ao caso) por querer seguir a risca todas as “boas praticas” que leu pela net.
Fico imaginando a cena de alguem que acabou de ler o artigo onde eh argumentado que “mvc nao eh OO” e, por tal razao, declara a todos da equipe de desenvolvimento que “…nao vamos mais usar mvc pq ele nao eh oo”.
De fato, Rafael, é arriscado se fiar na opinião de qualquer um que escreve um artigo. Todo mundo precisa saber pensar sobre o que lê.
O que eu achei interessante é o “absurdo” a que se chega quando se toma uma diretriz como se fosse um axioma absoluto. O projeto de um sistema envolve uma série de de escolhas de engenharia - se privilegia um aspecto em detrimento de outro. Isso talvez seja menos visível em software do que em outras áreas, porque as limitações físicas são muito menos importantes do que, por exemplo, ao se construir uma ponte.
O Holub acha que encapsulamento é uma regra inviolável. Mas, como os milhões de programas escritos usando MVC desde o smalltalk-80 mostram, é possível obter sistemas elegantes e funcionais relaxando um pouco o encapsulamento.
Um dos pontos que o artigo da javaworld nao fala sobre os getters eh o “problema da imutabilidade” das classes. O que alguns alegam eh que, tendo getters como temos a maior parte do tempo, as classes podem ter o status alterado facilmente. Imagine um codigo como
class TimerDoSistema {
private Date dataInterna;
public void init() {
this.dataInterna = new Date();
}
public Date getData() {
return this.dataInterna;
}
}
digamos que o a intencao era nao permitir que a data interna fosse alterada, e portando nao foi adicionado um setXxx(). O problema eh que, por estar o getData() retornando a referencia para a instancia da classe Date, qualquer metodo podera ser chamado, mudando as prpriedades internas:
TimerDoSistema t = new TimerDoSistema();
t.init();
// Altera a data
t.getData().setTime(System.currentTimeMillis());
A solucao para isso retornar uma copia ao inves da referencia. Porem, fazer isso somente “por fazer” - ou seja, sem a necessidade real de imutabilidade - somente teria resultados mais “desfavoraveis” que a favor.
O problema, porem, eh fazer 90% dos desenvolvedores entender isso.
Sei lá. Eu acho que imutabilidade na verdade deveria ser mais usada. Simplifica bastante o contrato da classe e vc não precisa se preocupar muito com mudança de hash-code. Além de poder dar alguma vantagem minuscula de performance (isso é secundário).
edição: Ficar copiando na hora de entregar para o cliente geralmente quer dizer q a classe do objeto retornado deveria ter sido imutavel. Acho q foi mancada da sun fazer o Date mutável.
DAO pode ser visto como um antipattern, mas também é solução pro caso de classes “Canivete Suiço”.
Eu acho que encapsulamento não pode ser tudo ou nada, tem que existir uma maior liberdade para outros objetos colaboradores olharem por traz da cortina.
Eu prefiro muito mais ter vários objetos colaborando entre sí que poucos objetos muito independentes. Essa é a velha discução de Coesão x Acoplamento e Spaghetti x Raviolli.
O problema de getters/setters é que eles foram criados para um modelo de componentes gambiarral (ou vocês realmente acham que JavaBeans não são uma gambiarra? Convenção de nomes só apra reflection?Habla sério…) que foge das boas práticas e tende para o aparecimento de objetos sem comportamento, só atributos.
O uso de boas práticas ou não realmente é uma decisão muito séria, mas acho que deve-se conehcer o máximo possível para se saber quando usar e quando não usar.
Não me lembro de nenhum padrão J2EE que não tenha sentido apenas para suprir uma deficiência da plataforma, mas o DAO, IMHO, é mais que isso, age na impedância (cadê o link apra aquele outro tópico?). É ideal? Claro que não, mas funciona (Como DTOs, que até hoje eu busco algo que possa eliminar).
Um DAO deve ler o estado de um objeto e persistí-lo, ou as outras letrinhas do CRUD. Extrair o estado de um objeto apenas com consultas quebra o encapsulamento (a menos que houvessem “friends” em Java), mas uma solução para quem procura se manter nas boas práticas é aplicar o pattern Memento e persistir o Memento. Isso é meio trabalhoso e agrega uma complexidade que, na prática, só vai ser útil para se persistir o objeto.
cv, e nos casos de outras consultas que retornam coleções de objetos Candidato? Em que lugar enfio estes métodos sem doer?
Estou lendo o segundo artigo que o AllMighty postou, estou até achando perigoso de tanto que estou adorando o que o cara está escrevendo. Faz um monte de sentido pra mim
O ActiveRecord (do Ruby On Rails, nao o Pattern) faz algo mais ou menos assim (traduzindo pra Java, e eu nao sei se acertei na sintaxe um-ponto-cincozenta):
[code]
public class Base {
public static T find(int id) { … }
public static Collection find_by_example(T example) { … }
public static Collection find_by_…
public T save() { … }
}
public class Candidato extends Base {
private String nome;
public void setNome(String nome) { … }
public String getNome() { … }
}[/code]
dai, em algum outro lugar…
Collection<Candidato> foo = Candidato.find(1);
foo.setNome("Coelhinho da Pascoa");
foo.save();
Interessante esta abordagem. Recentemente montei uma arquitetura pra um sistema que to fazendo e tinha feito algo semelhante.
A parte do save, update, etc eu fiz deste jeito mesmo sem VO e direto no proprio Bean, usando uns commands pra isso. Algo tipo:
public class User extends Bean
private String name;
private String lastName;
...
public void addUser() {
this.session.save(this);
}
Onde este atributo session é a implementacao de um interface que criei e tem somente os atributos save, update, delete, get e find. Somente ela reconhece o Dao.
Para a parte das consultas tava usando um ValueListHandle que era usado pelo meu Bean para realizar os find com as restricoes mais especificas. Nao ta gostando pq ia ter que ficar criando as classes do ValueListHandle dentro do bean e propagar a Session. Do jeito que o CV mostrou acho que resolvo meu problema com poucas alteracoes.
Poxa, chiquérrimo usando Generics. Ainda não me acostumei a pensar solução utilizando este recurso.
babando
Contudo, por que um objeto Candidato deveria ser responsável por buscar coleções de outros Candidatos? Por que ele deveria guardar informação sobre qual tipo de Candidato o usuário quer buscar?
E, nesse modelo, como sera possível alterar a classe Base para uma estrutura completamente diferente, baseado numa interface? Não seria melhor algo como
public class Candidato {
private Base<Candidato> base = factory.getBase();
private String nome;
public void setNome(String nome) { ... }
public String getNome() { ... }
}
O problema de fazer usando delegacao ao inves de heranca eh que vc tem que declarar os metodos estaticos
Eu nao sei se rola usar generics em metodos estaticos, alias… se nao der, a ideia do ActiveRecord nao fica tao legal, mas mesmo assim da pra aproveitar.
Por ultimo, concordo que usar um objeto Candidato pra buscar outros, mas usar a classe Candidato pra buscar fica chique - metodos estaticos bonitinhos e tal :mrgreen: