sábado, 17 de novembro de 2007

Analise Orientada a Objetos com Java - Parte 1

Estes dias eu me deparei com um problema bem interessante: uma forma de atribuir professores a disciplinas por meio de um sistema feito em Java.

Já aviso, estou tentando aprender e achei este exemplo interessante. Este post é uma tentativa de análise orientada à objetos feita de forma progressiva, comentários são bem vindos.

A primeira proposta foram 2 matrizes bidimensionais, uma com os professores disponíveis naquele dia e outra com as turmas, distribuidas ao longo de uma semana. Eu logo percebi que isso podia ser um problema de modelagem, pois se vc vai utilizar matrizes, paineis, interface textual ou seja lá o que for, isto é apenas uma camada - a visão. Um modelo muito mais rico pode ser criado, vejamos este exemplo em Java:

class Professor{}
class Disciplina{}
class Turma{
Disciplina disciplina;
Professor professor;
}
public class Main{
public static void main(String[] args) {
Professor oseias = new Professor();
Disciplina matematica = new Disciplina();
Turma matA = new Turma();

matA.disciplina = matematica;
matA.professor = oseias;
}
}


A minha classe Main mostra como seriam as operações sobre estas 3 classes. Basicamente eu tenho uma classe Professor, uma classe Disciplina e uma classe Turma. Se vc observarem qualquer instituição de ensino vão perceber que uma turma tem-um professor e tem-uma disciplina associados (composição).

Percebam também que eu não fui até uma escola ou universidade e fiquei horas levantando requisitos, criado diagramas uml ou documentos no word - apenas criei uma casca inicial de código (cheio de problemas por sinal). Também não me importo, ainda, com nenhum aspecto temporal. Sem falar que esta escola todos os professores podem dar qualquer disciplina - agora vamos implementar direito.

Vejamos... uma turma não troca de disciplina facilmente, mas de professor sim. Faz sentido, então, ter um setter de professor e um construtor que receba uma disciplina. Outra coisa, eu não defini nada nas outras classes, então está na hora de definir 2 atributos : id (numérico) e nome (String). Vou diferenciar os objetos pelo código, isto é, o seu id, e o nome será utilizado como descrição. Vou sobreescrever os métodos equals e toString.

Como o nome desses objetos é importante, vou coloca-los no construtor também (assim como o id).

class Professor{
long id;
private String nome;
public Professor(long id,String nome){
this.id = id;
this.nome = nome;
}
public long getId(){ return id; }
public String toString(){ return this.nome ; }
public boolean equals(Object o){
boolean test = false;

if (!(o instanceof Professor))
test = super.equals(o);
else
test = ((Professor) o).getId() == this.id;
return test;
}
}
class Disciplina{
long id;
private String nome;
public Disciplina(long id,String nome){
this.id = id;
this.nome = nome;
}
public long getId(){ return id; }
public String toString(){ return this.nome ; }
public boolean equals(Object o){
boolean test = false;

if (!(o instanceof Disciplina))
test = super.equals(o);
else
test = ((Disciplina) o).getId() == this.id;
return test;
}
}
class Turma{
long id;
private String nome;
private Disciplina disciplina;
private Professor professor;
public Turma(long id, String nome,Disciplina disciplina){
this.id = id;
this.nome = nome;
this.disciplina = disciplina;
}
public void setProfessor(Professor professor){
this.professor = professor;
}
public long getId(){ return id; }
public String toString(){
return this.nome + " [" + this.disciplina
+ "] c/ " + this.professor ;
}
public boolean equals(Object o){
boolean test = false;

if (!(o instanceof Turma))
test = super.equals(o);
else
test = ((Turma) o).getId() == this.id;
return test;
}
}
public class Main {
public static void main(String[] args) {
/* objetos bem comportados */
Professor oseias = new Professor(1L,"Oseias");
Disciplina matematica = new Disciplina(1L,"Matematica");
Turma matA = new Turma(1L,"Matematica A", matematica);
matA.setProfessor(oseias);

System.out.println("Professor " + oseias);
System.out.println("Disciplina " + matematica);
System.out.println("Turma " + matA);

/* objetos mal comportados
* Sujeitos a NullPointerException */
Professor juca = new Professor(2L,null);
Disciplina calculo = new Disciplina(2L,null);
Turma matB = new Turma(2L,"Matematica B", null);
matB.setProfessor(null); // nem precisava mas...
Turma matC = new Turma(3L,"Matematica C",calculo);
Turma matD = new Turma(4L,"Matematica D",calculo);
matD.setProfessor(juca);

System.out.println("Juca? " + juca);
System.out.println("Calculo?" + calculo);
System.out.println("matB? " + matB);
System.out.println("matC? " + matC);
System.out.println("matD? " + matD);
}
}


Mas que raios eu estou fazendo? veja a saída desse programa:

Professor  Oseias
Disciplina Matematica
Turma Matematica A [Matematica] c/ Oseias
Juca? null
Calculo?null
matB? Matematica B [null] c/ null
matC? Matematica C [null] c/ null
matD? Matematica D [null] c/ null


Qual o significado? Bom... eu tenho uma forma razoavel de representar um professor, disciplina e turma, porém não é pratico, o construtor está gigante e, em muitas situações, eu posso ter parâmetros nulos, o que pode ser uma fonte de problemas. Existem muitas formas de refatorar estas classes, eu nem toquei no HashCode, enfim, tem muito pano pra manga.

Apresento a vcs o desenvolvimento em etapas, iterativo. Eu estou chutando requisitos aos poucos, é verdade, mas eu entrego um codigo testável e completo e cada ciclo. Com os usuarios testando esse código (nesse caso, uma API, mas enfim...) eu obtenho um feedback interessante. O que vc acha?

2 comentários:

Marcio disse...

Eu acho que você deveria usar um problema mais complexo como exemplo e ver se isso realmente funciona. Seu exemplo é bem simples e todo mundo conhece o domínio (estou deduzindo que você estudou e fez faculdade :))

Acho que não é necessário coletar todos os requisitos possíveis e modelar todos os detalhes do sistema, mas é quase obrigatório um estudo do domínio e um design, nem que seja um rascunho, do sistema. Os outros detalhes surgirão com a implementação. :)

[]'s

NetWalker disse...

Saudações, sir Peczenyj. :)
Muito boa a abordagem da análise.
Java, como sempre, usual e prático no que diz respeito a conceitos de orientação a objeto (a não ser herança múlt... ops, heim? alguém disse algo? ah bom... :D ).
Pois bem, quero ver a segunda parte pra descobrir o que pretende com esses construtores.
No mais, já que Professores e Disciplinas são apenas referenciados em Turmas, e têm a sua existência independente destas, ainda acredito que a relação seria uma Agregação. E não Composição, como citou.
Voltando... Vc descreveu o problema como possuindo o objetivo de atribuir professores às disciplinas. Tem alguma restrição ou regra geral que o problema define e pretende seguir (disponibilidade, horários, etc)? Ou continuará o foco em relacionar professores e disciplinas sem maiores restrições?
Então é isso, continue o bom trabalho de sempre.
Abraço.
Até +.