sexta-feira, 14 de novembro de 2008

Novo Blog

Devido a questões de usabilidade, estou migrando meu blog e todas as postagens para o wordpress. Não deixe de visitar o novo espaço: http://germanofronza.wordpress.com/

Obrigado.

quinta-feira, 13 de novembro de 2008

Um domínio mais limpo...

A abordagem Domain-Driven-Design (ou apenas DDD), dentre várias boas características, tem contribuido para resgatar os originais valores das linguagens orientadas a objetos. Porém, isso só é possível graças aos "novos" frameworks baseados em classes POJOs, onde não somos obrigados a extender classes que não conhecemos. Agora as classes são baseadas em metadados através de anotações no próprio código Java, provendo maior flexibilidade devido ao desacoplamento com classes de frameworks.
Dentre todas as classes que compõem um domínio que faz uso de um mecanismo de persistência como a JPA, destacam-se as classes de entidades (Entity). Essas classes, que devem ser um espelho (orientado a objetos) da estrutura das entidades do banco de dados relacional, podem conter métodos de negócio que alteram ou acessam informações da base de dados. Mas para que esse acesso à base de dados dentro das classes de entidades possa ser feito, é necessário que todos os seus atributos estejam mapeados, para que quando instâncias dessas classes forem obtidas através do contexto de persistência (EntityManager ou mesmo uma Session do Hibernate Core), seus atributos também estejam no estado gerenciado (managed state). Se as classes de entidades forem implementadas dessa forma, não é necessário poluirmos elas com acesso à repositórios (implementados como DAOs, por exemplo). A Listagem 1, exemplifica a implementação de uma classe de entidade com todos os atributos mapeados.

@Entity
public class Curso {
@Id
@GeneratedValue
private Long id;

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name="Matricula",
joinColumns=@JoinColumn(name = "idCurso"),
inverseJoinColumns=@JoinColumn(name = "idAluno"))
private List alunos;

public Long getId() {
return this.id;
}

/** retorna uma lista read-only */
public List getAlunos() {
return Collections.unmodifiableList(this.alunos);
}

public boolean existeOuJaExistouAluno(Pessoa p) {
for(Pessoa aluno : this.alunos) {
if (p.equals(p) { // por seguir o pattern Entity, compara pelo ID.
return true;
}
}

return false;
}

public void matriculaPessoa(Pessoa p) {
this.alunos.add(p);
}

public void cancelaMatriculaAluno(Pessoa p) {
this.alunos.remove(p);
}
}
Nesta classe, é possivel notar que não a poluimos com getters e setters desnecessários. Para alterar o estado desse objeto, utilizamos os métodos de negócio nela contidos. A Listagem 2 mostra a implementação de um método que possui uma lista de pessoas e precisa verificar quais estão matriculadas em determinados cursos.

Setor s = repositorioSetor.getById(2L);
List
alunosDosCursosDoSetor = new ArrayList();
for(Pessoa p : pessoas) {
for (Curso c : s.getCursos()) {
if (c.
existeOuJaExistouAluno(p) {
alunosDosCursosDoSetor.add(p);
}
}
}
Esta implementação é muito mais OO do que a implementação mostrada na Listagem 3.
Setor s = repositorioSetor.getById(2L);
List
alunosDosCursosDoSetor = new ArrayList();
for(Pessoa p : pessoas) {
for (Curso c : s.getCursos()) {
if (
existeOuJaExistouAluno(c, p) {
alunosDosCursosDoSetor.add(p);
}
}
}
O método existeOuJaExistiuAluno (que tem mais aparência de função do que de método) teria que acessar o repositório de curso ou de pessoa e fazer um select para verificar se a pessoa está ou já foi matriculada no curso em questão. Isso é procedural demais!!

A idéia de ter um modelo mais orientado a objetos é que podemos ter um código muito mais próximo do negócio a ser tratado, facilitando o entendimento do mesmo tanto pelos técnicos (desenvolvedores) quanto pelos especialistas do negócio.