Super JavaBeans: Milagre ou Maldição?

Renato, discordo quando diz que “Além disso sua lógica fica preso ao tipo de persistência”, basta usar interfaces. Mas concordo com os outros pontos.

Colocar parte da lógica de persistência no objeto e outra parte em outro lugar para mim não faz sentido. Ou pretendem colocar aqueles maravilhos métodos de busca com 75 argumentos no Aluno?

E outro problema: o método “save” é chamado no server, certo? Mas o objeto também existe no cliente em aplicações não-web. Como proceder então? throw new ChamouOMetodoNoLugarErradoSeuBurro? Prefiro não.

Consertando o exemplo, entao, e usando o exemplo da classe Base que eu dei no outro topico (valeu pelo link, Luiz):

[code]public class Sala extends Base {
private String nome;
private Set alunos;

public void setNome(String nome) { … }
public String getNome() { … }

public void addAluno(Aluno aluno) { … }
public void removeAluno(Aluno aluno) { … }
public Set getAlunos() { … }
}[/code]

public class Aluno extends Base<Candidato> { private String nome; public void setNome(String nome) { ... } public String getNome() { ... } }

Levando em conta que os metodos save, load, find e tudo mais estao na classe Base, e pra piorar um pouco alguns deles sao estaticos (pq nao faz sentido usar uma instancia de Aluno pra procurar outros), o codigo ate que fica simplezinho.

Um problema, no entanto, eh quando voce quer testar esse treco sem ter que ir pro banco de dados de verdade. Como nao da pra sobrescrever Base.save() so de alegria, o que vc pode fazer eh algo mais ou menos assim:

[code] public class Base {

private static Session session;
public static void setSession(Session session) { … }


}[/code]

Onde Session eh uma Session do Hibernate, mesmo. Num teste unitario, tudo que voce precisa fazer eh chamar setSession e passar um mock, e garantir que o comportamento ta certinho.

Falei merda? :slight_smile:

[quote=LIPE]
E outro problema: o método “save” é chamado no server, certo? [/quote]

[momento viagem ao mundo utopico]
o problema: a menos que seja algo funcional, essa droga de método não deveria existir!
[/momento viagem ao mundo utopico]

Se infelizmente ele existe, se precisamos controlar a persistência na mão mesmo, a pergunta:

  • Coordenar a persistência por caso de uso (por funcionalidade, na verdade) é legal?

Eu acho que é o jeito mais “limpinho” sem macumba, mas me encomoda. Você acaba endo muitos pseudo-façades coordenando os dados no seu sistema…

Voltando ao tema central…

O Gavin King deu uma palestra anteontem (Sábado) no RioJavaSummit e colocu uma coisa bem interessante:

“Com o EJB 3.0, EJBs são os novos JavaBeans”, eu encaro isso no sentido que eles representam um modelo que foi introduzido pelos beans clássicos, mas de uma outra maneira. Beans clássicos possuem “injeção de dependência manual”, os ejbs já utilizam IoC…

Independente da minha opinião sobre a spec do EJB 3.0, achei um ponto bem interessante.

É isso que não me entra na cabeça, um objeto ser responsável por persistir ele mesmo, ou ser responsável por ações com diversos objetos do mesmo tipo.
Desta forma não estaríamos ferindo a regra de responsabilidades?
E particularmente eu acho que separar por responsabilidades fica mais fácil de se manter.

Rafael, pra evitar que cada um va pra um lado na conversa, e pra evitar confusao: qual eh a sua definicao de “regra de responsabilidade” que fazer isso estaria ferindo?

Eu me referia particularmente a:

[code]public class Aluno{
public void save(Aluno aluno){…}
public void delete(Aluno aluno){…}

}
[/code]

Não consigo entender/aceitar um aluno salvar ou deletar ele mesmo, pois cada objeto/camada/ou sei lá o quê deveria ser reponsável por algo em específico. Por exemplo eu teria um Aluno responsável por validar e modificar as informações que um aluno tem, e um outro objeto (provavelmente um DAO), responsável por persistir o Aluno.
Ao menos foi assim que aprendi e venho fazendo.

Obs:Acabei de notar que DAO passou a ser uma obrigação pra mim, não um padrão sugerido.

:cry: :cry: :cry: UUuááááá que preconceito. Não posso programar em Java coisas simples?? Pode ser simples mas se eu quiser multiplataforma uáááááááááááá

Bom, é por que toda vez que você for usar a lógica vai ter que se preocupar em salvar os objetos, e isso não é natural. É isso?

[color=red]Compile Error[/color]

Eu não sei nada de UML :smiley:


Bom na aplicação que fiz com um colega temos o seguinte cenário:

Um módulo web de uma aplicação de help desk. Basicamente são duas coisas que o sistema faz: cadastra uma nova solicitação de atendimento, e consulta o status de um atendimento efetuado.

A lógica é simples acesso a banco, exceto o lance de converter datas. Nós criamos então as classes organizadas assim:

  • pacote “logica”: A lógica da aplicação, são as classes DataAccess que é um DAO e DateConverter para converter datas;
  • pacote “dados”: Service, ServiceRequest, HistoryItem. São as “entidades” da aplicação, são beans burros.

Assim se eu quero abrir uma solicitação eu crio um ServiceRequest e peço pro DAO gravá-lo. Se eu quero consultar o andamento de um atendimento, eu peço pro DAO me devolver um Service para consultar.

Assim é a camada controladora (num MVC) é que instancia o DAO, que na verdade contém toda a lógica (pouca), cria os beans e pede para salvá-os. Se houvesse mais lógica não relacionada a persistência, eu vou criando classes separadas (quanto menos melhor) como por exemplo DateConverter, e as usando sobre minhas entidades. Ou poderia embutir tal lógica nos beans, tornando-os mais inteligentes e mais “OO”. Mas não fiz isso (p.e. não coloquei a conversão de datas embutida e sim na parte “logica”) porque achei que tinha que ser assim, por causa do DTO/VO.

É isso aí. Que Zahl me ajude, ou Jesus Cristo.

Qual a sua opinião?

[quote=LIPE]Renato, discordo quando diz que “Além disso sua lógica fica preso ao tipo de persistência”, basta usar interfaces. Mas concordo com os outros pontos.
[/quote]

É aquilo que eu disse, mesmo com interfaces você deixa “marcas” de persistência dentro da lógica. Sua lógica fica dependente das interfaces e não podem ser reutilizadas fora de um contexto “persistencial”. É o que eu acho.

Esse se a gente tivesse uma classe que identificasse o registro e outra a coleção de registros não ficaria mais decente.
ex:

class Funcionario
{
private int codigo;
private String nome;
// setters e getters
}

class Funcionarios
{
private Funcionarios() {}

public static void adicionar(Funcionario func)
{

}

public static void remover(int codigo)
{

}
}

Funcionario funcionario = new Funcionario()
funcionario.setCodigo(1);
funcionario.setNome(“Maria”);
Funcionarios.adicionar(funcionario);

Sei lá, isso não seria mais intuitivo.
Uma coleção de funcionarios que adiciona para sua lista um funcionario.
Ela não é instanciável, pois não representa uma instancia, mais sim um colecão de instancias.

Renato, falei aquilo pois você disse “Além disso sua lógica fica preso ao tipo de persistência”. Considerando sua retificação concordo completamente.

jprogrammer, desta maneira você só renomeou a classe FuncionarioDAO para Funcionarios hehe

Então o DAO não é tão grotesco assim.
Não interessa a implementação, o que importa é a interface.
Para o restante do sistema, você estará adicionando, retirando, recuperando itens de uma lista, e não persistindo em um banco.
Não sei o que tem de errado um método com um nome “salvar”, “adicionar”, que neste caso indentifica uma operação do sistema.
Poderia ser faturar, descontar, processar, matricular, internamente ele poderia fazer qualquer coisa.
Se o caso de uso for inserir funcionário , não tem problema algum.

jprogrammer, após a postagem do Shoes ficou bem claro que DAO não é grotesco, é apenas um aspecto do sistema.

hum, esse é o objetivo de DAOs, persistir o objeto, não importa onde. Se é numa Collection em memória ou enviando mensagens para um cara com uma máquina de escrever digitando todos os dados.

interface DAO{
    public void salvar( Object obj );
}

class BancoDAO implements DAO {
    public void salvar( Object obj ) {
       connection.save( obj );
    }
}

class CaraDaMaquinaDeEscreverDAO implements DAO {
    public void salvar( Object obj ) {
        messenger.send( obj );
    }
}

Ainda mais implementado com Generics, como o cv sugeriu.

Sim, o objetivo do DAO é persisitir no banco ou em qualquer outro lugar.
Mas para o restante do sistema, ele não faz isso, é apenas uma implementação interna do DAO.

Isto só é verdade utilizando AbstractFactories ou IoC :wink:

[quote=cv]Eu tou usando active records, shoes, e funciona legal tambem. Em Java eh mais pentelho de implementar (mas eu cheguei a dar um exemplo pro Lipe naquela thread sobre encapsulamento… alguem linka pra mim?) de como a coisa funciona mais ou menos.

A diferenca eh que em Ruby nao tem nada da enchecao de saco :mrgreen: [/quote]

Eu tava pensando sobre como o pattern de unit of work poderia ajudar nesse caso.
O padrão prega que uma entidade externa controle a persistencia do modelo. Com um pouco de AOP isso ficaria quase transparente.
Então em vez de fazer:

 Aluno aluno = new Aluno.create("Rocky Balboa", sala);
 aluno.save(); // insert into alunos values ('Rocky Balboa', 12);

Ficaria:

 Aluno aluno = new Aluno("Rocky Balboa", sala);

Isso, claro, funciona para exemplos e programas de demonstraçãoo, seria necessario uma API intrusiva para apagar entidades, marcar como transientes e fazer detachment para funcionar no mundo real. Ou alguma coisa que não saquei.

Poderiamos ser ainda mais malignos com AOP e fazer o seguinte:

 Aluno aluno = new Aluno(1234); //<-- primary key dele

Na verdade com AOP poderiamos detectar o movimento labial do usuário e gravar um novo Aluno quando ele fizesse o som de bolinhas de sabão estourando :XD:

Lipe, que não gosta do que teme.

pop :mrgreen:

Sei nao, usar AOP demais me estragou e ate hoje eu ainda frequento grupos de apoio. Usar uma linguagem mais dinamica tem funcionado bem, grassadeus :mrgreen:

No caso de marcar como transientes, não é possivel usar a mesma abordagem do Hibernate não? Tipo, se o id está com o valor indicado pelo unsaved-value, então o treco é transiente.

valeuz…