aluno: Alexandre Couto Albizzati
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 06/08/2008 (2)
Introdução
A idéia deste lab foi ampliar o programa desenvolvido no lab1.
A primeira parte consistiu em, a partir do lab1, criar uma classe simulador, que contivesse a função main. A segunda parte foi ampliar as possibilidades para os tipos de alunos, alterando um pouco a estrutura das classes e criando uma classe Queue, para fazer o trabalho que RelaQueue fazia, porém usando tipos genéricos.
Trabalhou-se nesse lab com o tratamento de Exceções, gerando restrições no momento da criação de algumas características dos alunos.
No final foi ainda necessário ajustar a classe simulador para esta nova estrutura.
Desenvolvimento
Os tipos de aluno diferentes agora são muitos.
A classe aluno tornou-se concreta e criou-se uma classe abstrata chamada Comportamento. Esta classe admite 6 subclasses: Esforçado, SafoPreguicoso, Summa, Pemba, Burro e Imprevisivel. Dessa forma ganhamos em desacoplamento, já que Aluno apenas precisa ter um "comportamento", não sendo necessário duplicação de código.
A classe aluno ainda possui três subclasses para dizer de onde é o aluno: AlunoITA, AlunoUSP e AlunoUnicamp. Estas classes possuem algumas restrições, estabelecidas por meio do tratamento de exceções.
Pergunta: "De que outra forma você resolveria os problemas expostos acima?"
Resposta: Poderia resolver implementando interfaces. Os alunos poderiam implementar um comportamento por meio de interfaces, o que os forçaria a ter um comportamento, ao mesmo tempo que evitaria duplicação de código desnecessariamente.
As principais mudanças das classes são mostradas abaixo.
A classe Aluno deixou de ser abstrata e agora possui uma variável do tipo Comportamento. A classe Comportamento é abstrata, possuindo os dois métodos abstratos: getInteligencia() e getDediacacao().
A classe Comportamento possui 6 subclasses (já citadas) que, além de sobreescreverem os dois métodos abstratos de Comportamento, ainda possuem um construtor que apenas faz referência ao construtor de sua superclasse. Como exemplo tempos o código do contrutor da subclasse Esforcado:
public Esforcado(Aluno aluno) { super(aluno); }
O construtor de Comportamento é mostrado abaixo:
public Comportamento(Aluno al) { aluno = al; }
O construtor de Aluno:
// Construtor public Aluno(String nome, RelaQueue relaQueue) { this.comportamento = new Esforcado(this); this.nome = nome; this.queue = relaQueue; }
Dessa forma, quando aluno é criado, tem como variável de instância "comportamento", e como padrão, ela é do tipo Esforcado. O método setComportamento() permite alternar entre outros tipos. Ele é mostrado abaixo:
public void setComportamento(Comportamento comport) throws Exception { this.comportamento = comport; }
É importante observar ainda que Aluno possui os métodos getInteligencia() e getDedicacao(), mas no fundo estes são invocações dos métodos getInteligencia() e getDedicacao() de sua variavel comportamento:
public double getInteligencia() { return this.comportamento.getInteligencia(); } public double getDedicacao() { return this.comportamento.getDedicacao(); }
A classe Aluno ainda pode ter três subclasses diferentes: AlunoITA, AlunoUSP e AlunoUnicamp.
Cada uma destas subclasses possuem restrições que foram tratadas utilizando Exception.
O código de AlunoITA é mostrado abaixo:
public class AlunoITA extends Aluno { public AlunoITA(String nome, RelaQueue relaQueue) { super(nome,relaQueue); } public void setComportamento(Comportamento comportamento) throws Exception { if(comportamento instanceof Burro) throw new Exception(); //iteanos não são burros! super.setComportamento(comportamento); //faz o que a superclasse Aluno faz. } }
A classe RelaQueue tornou-se uma subclasse da nova classe Queue. A classe RelaQueue esvaziou-se e o seu conteúdo foi tranferido para a classe Queue, sofrendo algumas adaptações para lidar com o tipo genérico. O algoritmo, contudo, permaneu o mesmo. Tentei utilizar a classe Vector, mas não consegui, então optei por utilizar array.
O código da classe Queue é mostrado abaixo:
import java.util.*; public class Queue<T extends Object> { private Object[] array = new Object[10]; private int inicio=0; private int fim=0; //Metodos queue e dequeue public void queue(T elem) { // Maximo de 10 elementos if((fim+1)==inicio||(fim+1)==(inicio+10)) { System.out.println("Fila cheia!"); } else { array[fim]=elem; fim = (fim + 1) % 10; } } public T dequeue() { T valor; valor = (T)array[inicio]; if(inicio!=fim) { inicio = (inicio + 1) % 10; return valor; } else return null; } public int getInicio() { return inicio; } public int getFim() { return fim; } }
A classe Simulador antes das alterações é mostrada abaixo:
import java.io.Console; import java.io.PrintWriter; import java.util.Arrays; import java.io.IOException; public class Simulador { public static void main(String[] args) { Aluno[] alunos = new Aluno[20]; Console console = System.console(); String nome; String tipo; RelaQueue relaQueue = new RelaQueue(); Professor professor = new Professor(relaQueue); int i=0; if(console != null) { //String name = console.readLine("Entre com o numero de alunos: "); String var = console.readLine("Vc deseja cadastrar novo aluno? (s/n)"); if(var.equals("s")){ while(var.equals("s")) { nome = console.readLine("Entre com o nome do aluno: "); tipo = console.readLine("Qual o tipo do seu aluno? 'esforcado' ou 'safopreguicoso'?"); if(tipo.equals("esforcado")) alunos[i] = new AlunoEsforcado(nome,relaQueue); else if(tipo.equals("safopreguicoso")) alunos[i] = new AlunoSafoPreguicoso(nome,relaQueue); alunos[i].fazEEntregaRelatorio(); i++; var = console.readLine("Vc deseja cadastrar novo aluno? (s/n)"); } professor.corrigirRelatorios(); } } } }
Um exemplo da execução:
A classe Simulador com as alterações já implementadas é mostrada logo abaixo:
import java.io.Console; import java.io.PrintWriter; import java.util.Arrays; import java.io.IOException; public class Simulador { public static void main(String[] args) { Aluno[] alunos = new Aluno[20]; Console console = System.console(); String nome; String instituto; String tipo; RelaQueue relaQueue = new RelaQueue(); Professor professor = new Professor(relaQueue); int i=0; if(console != null) { //String name = console.readLine("Entre com o numero de alunos: "); String var = console.readLine("Vc deseja cadastrar novo aluno? (s/n)"); if(var.equals("s")){ while(var.equals("s")) { nome = console.readLine("Entre com o nome do aluno: "); instituto = console.readLine("Qual a instituição de seu aluno: 'ITA', 'USP' ou 'Unicamp?'"); if(instituto.equals("ITA")) alunos[i] = new AlunoITA(nome,relaQueue); else if(instituto.equals("USP")) alunos[i] = new AlunoUSP(nome,relaQueue); else if(instituto.equals("Unicamp")) alunos[i] = new AlunoUnicamp(nome,relaQueue); tipo = console.readLine("Qual o tipo do seu aluno? 'esforcado', 'preguicoso', 'summa', 'pemba', 'burro' ou 'imprevisivel'?"); if(tipo.equals("esforcado")) { try { alunos[i].setComportamento( new Esforcado(alunos[i]) ); }catch (Exception e) { System.out.println("Nao deveria lançar erro!"); } } else if(tipo.equals("preguicoso")) { try { alunos[i].setComportamento( new SafoPreguicoso(alunos[i]) ); }catch (Exception e) { System.out.println("Soh iteanos sao safos!"); } } else if(tipo.equals("summa")) { try { alunos[i].setComportamento( new Summa(alunos[i]) ); }catch (Exception e) { System.out.println("Soh iteanos sao summas!"); } } else if(tipo.equals("pemba")) { try { alunos[i].setComportamento( new Pemba(alunos[i]) ); }catch (Exception e) { System.out.println("Nao deveria dar erro!"); } } else if(tipo.equals("burro")) { try { alunos[i].setComportamento( new Burro(alunos[i]) ); }catch (Exception e) { System.out.println("Iteanos nao podem ser burros!"); } } else if(tipo.equals("imprevisivel")) { try { alunos[i].setComportamento( new Imprevisivel(alunos[i]) ); }catch (Exception e) { System.out.println("Nao deveria dar erro!"); } } alunos[i].fazEEntregaRelatorio(); i++; var = console.readLine("Vc deseja cadastrar novo aluno? (s/n)"); } professor.corrigirRelatorios(); } } } }
É interessante observar que uma melhoria que poderia ter sido implementada no meu código é um tratamento para a situação em que o operador digita errado o tipo de aluno. (Não tratei esse tipo de erro, assumindo que o operador sempre irá digitar corretamente as entradas).
Um exemplo da execução:
O Diagrama das Classes no BlueJ ficou no final como mostrado abaixo:
Criou-se ainda a classe de testes para verificação do programa. O resultado dos testes é mostrado abaixo:
Conclusão
Neste lab implementaram-se algumas idéias de padrões de projeto para aumentar o desacoplamento e a coesão entre as classes. Por causa disso, observamos que embora tenhamos aumentado bastante o código, não foi necessário alterar outros pontos como a classe Professor, por exemplo, em outras classes, graças ao desacoplamento entre elas.
Implementamos a classe Simulador, para realmente poder rodar o programa, não ficando apenas nos testes.
Utilizou-se ainda o tratamento de exceções para gerar restrições nas subclasses AlunoITA, AlunoUSP e AlunoUnicamp.
Exploramos também o uso de genéricos, gerando a classe Queue e tornando a RelaQueue uma subclasse daquela.






Bom rela e prática, tudo ok.