aluno: Misael Feitosa Alexandre
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 07/09/2008 (6)
Introdução
Este laboratório consistiu em uma modificação do primeiro laboratório de forma a torná-lo mais abrangente e flexível ao inserir novos conceitos de Orientação a Objetos e interação com o usuário. Dentre os conceitos novos aplicados, pode-se citar o tratamento de excessões (Exceptions) e o uso de genéricos.
Desenvolvimento
Inicialmente foram feitas modificações na forma de tratamento do comportamento do aluno. Tais modificações visaram tornar o comportamento mais flexível para, dentre outras coisas, suportar mudanças.
Foi então criada uma classe abstrata Comportamento, a qual estava ligada diretamente a um aluno. Tal classe teve então os métodos abstratos getInteligencia() e getDedicacao().
Classe Comportamento
public abstract class Comportamento { private Aluno aluno; //Construtor que recebe o Aluno "dono" do comportamento public Comportamento(Aluno aluno){ this.aluno=aluno; } //Métodos abstratos a serem escritos nas subclasses public abstract double getInteligencia(); public abstract double getDedicacao(); }
A partir da classe abstrata Comportamento (geral), foram criadas subclasses específicas que continham os comportamentos específicos. Além dos comportamentos Esforcado e SafoPreguicoso, foram criados os comportamentos Imprevisivel, Burro, Pemba e Summa. Todas estas subclasses concretas tratavam a inteligencia e dedicacao do aluno de acordo com suas características e implementavam os métodos getInteligencia() e getDedicacao().
O códigos das classes pode ser visto abaixo:
Classe Esforcado
public class Esforcado extends Comportamento { public double inteligencia, dedicacao; public Esforcado(Aluno aluno) { super(aluno); this.inteligencia=0.5; this.dedicacao=1; } public double getInteligencia(){ return this.inteligencia; } public double getDedicacao(){ return this.dedicacao; } }
Classe SafoPreguicoso
import java.util.*; public class SafoPreguicoso extends Comportamento { public double inteligencia, dedicacao; public SafoPreguicoso(Aluno aluno) { super(aluno); this.inteligencia=1; } private static double generateRandomDe0aMeio() { Random generator = new Random(); double r = generator.nextDouble(); return r * 0.5; } public double getInteligencia(){ return this.inteligencia; } public double getDedicacao(){ this.dedicacao=generateRandomDe0aMeio(); return this.dedicacao; } }
Classe Burro
public class Burro extends Comportamento { public double inteligencia, dedicacao; public Burro(Aluno aluno) { super(aluno); this.inteligencia=0; this.dedicacao=0; } public double getInteligencia(){ return this.inteligencia; } public double getDedicacao(){ return this.dedicacao; } }
Classe Pemba
import java.util.*; public class Pemba extends Comportamento { public double inteligencia, dedicacao; public Pemba(Aluno aluno) { super(aluno); } private static double generateRandomDe0aMeio() { Random generator = new Random(); double r = generator.nextDouble(); return r * 0.5; } public double getInteligencia(){ this.inteligencia=generateRandomDe0aMeio(); return this.inteligencia; } public double getDedicacao(){ this.dedicacao=generateRandomDe0aMeio(); return this.dedicacao; } }
Classe Imprevisivel
import java.util.*; public class Imprevisivel extends Comportamento { public double inteligencia, dedicacao; public Imprevisivel(Aluno aluno) { super(aluno); } private static double generateRandomDe0aUm() { Random generator = new Random(); double r = generator.nextDouble(); return r * 1; } public double getInteligencia(){ this.inteligencia=generateRandomDe0aUm(); return this.inteligencia; } public double getDedicacao(){ this.dedicacao=generateRandomDe0aUm(); return this.dedicacao; } }
Classe Summa
public class Summa extends Comportamento { public double inteligencia, dedicacao; public Summa(Aluno aluno) { super(aluno); this.inteligencia=1; this.dedicacao=1; } public double getInteligencia(){ return this.inteligencia; } public double getDedicacao(){ return this.dedicacao; } }
Feito tal, modificou-se então a classe Aluno. Tal classe virou concreta e, para implementar os comportamentos, foi criada uma variável interna comportamento que determina o comportamento atual do aluno, ou seja, pode haver mudanças. Foram criados também os métodos getInteligencia() e getDedicacao(), que delegavam seu valor à variável comportamento. Convém salientar que o comportamento inicial de um aluno criado é Esforcado (criado no construtor).
Classe Aluno
public class Aluno { public String nome; public int conhecimento; public RelaQueue queue; public Comportamento comportamento; //Cria novo aluno com comportamento inicial Esforcado public Aluno(String nome,RelaQueue queue){ this.nome=nome; this.queue=queue; conhecimento=0; this.comportamento=new Esforcado(this); } public int getConhecimento(){ return this.conhecimento; } //Delega getConhecimento e getInteligencia à variável comportamento public double getInteligencia(){ return this.comportamento.getInteligencia(); } public double getDedicacao(){ return comportamento.getDedicacao(); } //Seta um novo comportamento com tratamento de Exceptions public void setComportamento(Comportamento comportamento) throws Exception{ this.comportamento=comportamento; } public String getNome(){ return nome; } public void fazEEntregaRelatorio(){ double qualidade = (2 * this.getDedicacao() + 1 * this.getInteligencia() ) / 3 ; double originalidade = (1 * this.getDedicacao() + 2 * this.getInteligencia() ) / 3 ; Relatorio rela=new Relatorio(qualidade, originalidade, this); this.queue.queue(rela); conhecimento=conhecimento+1; } }
Para que um aluno possa ter uma universidade, foram criadas subclasses de Aluno chamadas AlunoITA, AlunoUnicamp e AlunoUSP. Entretanto, foram implementadas restrições de forma que os alunos do ITA nunca podem ser Burros, e os alunos da USP e Unicamp nunca serão nem Summas nem SafosPreguicosos. Para que tais restrições fossem implementadas, foi usado tratamento de Exceptions.
Os códigos das classes AlunoITA, AlunoUnicamp e AlunoUSP podem ser vistos abaixo.
Classe AlunoITA
public class AlunoITA extends Aluno { //Construtor igual ao da classe Aluno public AlunoITA(String nome,RelaQueue queue) { super(nome,queue); } //Seta o comportamento lançando uma Exception se ele for instancia //da Classe Burro. public void setComportamento(Comportamento comportamento) throws Exception{ if (comportamento instanceof Burro){ throw new Exception(); } super.setComportamento(comportamento); } }
Classe AlunoUSP
public class AlunoUSP extends Aluno { //Construtor igual ao da classe Aluno public AlunoUSP(String nome,RelaQueue queue) { super(nome,queue); } //Seta o comportamento lançando uma Exception se ele for instancia //da Classe Summa ou da Classe SafoPreguicoso. public void setComportamento(Comportamento comportamento) throws Exception{ if (comportamento instanceof Summa || comportamento instanceof SafoPreguicoso) throw new Exception(); super.setComportamento(comportamento); } }
Classe AlunoUnicamp
public class AlunoUnicamp extends Aluno { //Construtor igual ao da classe Aluno public AlunoUnicamp(String nome,RelaQueue queue) { super(nome,queue); } //Seta o comportamento lançando uma Exception se ele for instancia //da Classe Summa ou da Classe SafoPreguicoso. public void setComportamento(Comportamento comportamento) throws Exception{ if (comportamento instanceof Summa || comportamento instanceof SafoPreguicoso) throw new Exception(); super.setComportamento(comportamento); } }
Foi então criada uma Classe chamada Simulador, que tinha um método main e visava interação com o usuário, de forma que o usuário pudesse criar quantos alunos quisesse, indicando, para cada um, sua universidade e seu comportamento. Se tais comportamentos não fossem possíveis dada certa universidade, era lançada uma Exception como já mostrado acima.
Classe Simulator
import java.util.Scanner; public class Simulator { public static void main(String args[]) { //Criado variáveis iniciais Aluno[] vetor_aluno=new Aluno[50]; String universidade, comportamento; RelaQueue queue=new RelaQueue(); int num; //Criado um scanner de teclado Scanner scan = new Scanner (System.in); scan.useDelimiter("\n"); //Entra-se com o numero de alunos System.out.println("Entre com o número de alunos"); String numero=scan.next(); num=Integer.parseInt(numero); //Para cada um dos alunos... for (int i=0;i<num;i=i+1) { //Entra-se com o nome do aluno System.out.println("Entre com o nome do aluno "+(i+1)+": "); String nome=scan.next(); //Entra-se com a universidade do aluno do{ System.out.println("Entre com a universidade do aluno "+(i+1)+" (ITA, USP ou Unicamp): "); universidade=scan.next(); } while (!universidade.equals("ITA")&&!universidade.equals("USP")&&!universidade.equals("Unicamp")); if (universidade.equals("ITA")){ vetor_aluno[i]=new AlunoITA(nome, queue); } else if (universidade.equals("Unicamp")){ vetor_aluno[i]=new AlunoUnicamp(nome, queue); } else{ vetor_aluno[i]=new AlunoUSP(nome, queue); } //Entra-se com o comportamento do aluno do{ System.out.println("Entre com o comportamento do aluno "+(i+1)+" (Imprevisivel,Burro,Pemba,SafoPreguicoso,Summa,Esforcado): "); comportamento=scan.next(); } while (!comportamento.equals("SafoPreguicoso")&&!comportamento.equals("Burro")&&!comportamento.equals("Pemba")&&!comportamento.equals("Imprevisivel")&&!comportamento.equals("Summa")&&!comportamento.equals("Esforcado")); //Dado o comportamento, tenta-se setar o mesmo para o aluno. Não //havendo possibilidade, trata-se a Exception if (comportamento.equals("Esforcado")){ Esforcado comp=new Esforcado(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } else if (comportamento.equals("Burro")){ Burro comp=new Burro(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } else if (comportamento.equals("Imprevisivel")){ Imprevisivel comp=new Imprevisivel(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } else if (comportamento.equals("Summa")){ Summa comp=new Summa(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } else if (comportamento.equals("SafoPreguicoso")){ SafoPreguicoso comp=new SafoPreguicoso(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } else{ Pemba comp=new Pemba(vetor_aluno[i]); try{ vetor_aluno[i].setComportamento(comp); } catch(Exception e){ System.out.println("Voce tentou fazer algo impossivel"); } } } //Faz e entrega o relatorio de todos os alunos for (int i=0;i<num;i=i+1) { vetor_aluno[i].fazEEntregaRelatorio(); } } }
Por fim, implementando o uso de genéricos, foram feitas modificações na Classe RelaQueue. Foi inicialmente criado uma Queue genérica, que não necessariamente era feita de objetos da Classe Relatorio, chamada Queue<T>. A Classe RelaQueue passou então a ser subclasse de Queue<Relatorio> (definindo que T neste caso era Relatorio). Os códigos de Queue<T> e RelaQueue podem ser vistos abaixo.
Classe Queue<T>
public class Queue<T> { //Cria array de objetos genéricos private Object[] array=new Object[50]; private int inicio=0; private int fim=0; private T valor; //coloca um objeto na pilha public void queue(T elem) { array[fim]=elem; fim=(fim+1)%10; } //retira um objeto da pilha public T dequeue(){ valor=(T)array[inicio]; if (fim==inicio){ valor=null; } inicio=(inicio+1)%10; return valor; } }
Classe RelaQueue
//Herda de Queue<Relatorio> (faz T igual a Relatorio) public class RelaQueue extends Queue<Relatorio>{ }
As outras Classes continuaram da mesma maneira do primeiro laboratório.
TESTES
Foi criada uma classe de testes, que testava a compatibilidade com o laboratório passado e as novas funcionalidades
Classe Teste
public class teste extends junit.framework.TestCase { public void testFuncionaComoOLab1() { //criando os objetos RelaQueue queue = new RelaQueue(); Professor prof = new Professor(queue); // O que muda em termos de interface externa neste lab, // é a criação dos alunos. O que mostra que o nosso código // está bem desacoplado e a nossa refatoração não alterou // o funcionamento dos outros objetos (Professor, Relatório, etc). Aluno aluno1 = new Aluno("John Smith", queue); Aluno aluno2 = new Aluno("Mark Smith", queue); Aluno aluno3 = new Aluno("Joseph Smith", queue); Aluno aluno4 = new Aluno("Robert Smith", queue); try { aluno3.setComportamento( new SafoPreguicoso(aluno3) ); aluno4.setComportamento( new SafoPreguicoso(aluno4) ); } catch (Exception e) { fail("Não deveria lançar erro!"); } //teste de alunoesforcado assertEquals(0.5, aluno1.getInteligencia(), 0.01); assertEquals(1, aluno1.getDedicacao(), 0.01); //teste de alunosafo assertEquals(1.0, aluno3.getInteligencia(), 0.01); assertTrue(aluno3.getDedicacao() != aluno3.getDedicacao()); //deve ser randomica assertTrue(aluno3.getDedicacao() < 0.5); //alunos comecam a fazer os relas aluno1.fazEEntregaRelatorio(); //roubamos o relatório do primeiro aluno para investigá-lo Relatorio rela1 = queue.dequeue(); assertEquals(aluno1, rela1.getAluno()); assertTrue(rela1.getAluno().getNome().equals("John Smith")); assertTrue(rela1.getQualidade() < 0.9); assertTrue(rela1.getQualidade() > 0.8); assertTrue(rela1.getOriginalidade() < 0.7); assertTrue(rela1.getOriginalidade() > 0.6); //os outros continuam a fazer os relas aluno2.fazEEntregaRelatorio(); aluno3.fazEEntregaRelatorio(); aluno4.fazEEntregaRelatorio(); //deve exibir a coreção dos relas dos aluno2, aluno3, e aluno4, nesta ordem //pois "roubamos" o relatório do aluno1 prof.corrigirRelatorios(); } public void testOsComportamentosFuncionamComoEspecificado() { RelaQueue queue = new RelaQueue(); Aluno aluno1 = new Aluno("John", queue); Comportamento summa = new Summa(aluno1); Comportamento pemba = new Pemba(aluno1); Comportamento imprevisivel = new Imprevisivel(aluno1); Comportamento safo = new SafoPreguicoso(aluno1); Comportamento esforcado = new Esforcado(aluno1); Comportamento burro = new Burro(aluno1); //teste de esforcado assertEquals(0.5, esforcado.getInteligencia(), 0.01); assertEquals(1, esforcado.getDedicacao(), 0.01); //teste de burro assertEquals(0.0, burro.getInteligencia(), 0.01); assertEquals(0.0, burro.getDedicacao(), 0.01); //teste de summa assertEquals(1.0, summa.getInteligencia(), 0.01); assertEquals(1.0, summa.getDedicacao(), 0.01); //teste de safo assertEquals(1.0, safo.getInteligencia(), 0.01); assertTrue(safo.getDedicacao() != safo.getDedicacao()); //deve ser randomica assertTrue(safo.getDedicacao() < 0.5); //teste de imprevisivel assertTrue(imprevisivel.getInteligencia() != imprevisivel.getInteligencia()); //deve ser randomica assertTrue(imprevisivel.getInteligencia() < 1.0); assertTrue(imprevisivel.getDedicacao() != imprevisivel.getDedicacao()); //deve ser randomica assertTrue(imprevisivel.getDedicacao() < 1.0); //teste de pemba assertTrue(pemba.getInteligencia() != pemba.getInteligencia()); //deve ser randomica assertTrue(pemba.getInteligencia() < 0.5); assertTrue(pemba.getDedicacao() != pemba.getDedicacao()); //deve ser randomica assertTrue(pemba.getDedicacao() < 0.5); } public void testAsSubClassesDeAlunoTemRestricoes() { RelaQueue queue = new RelaQueue(); AlunoITA alunoITA = new AlunoITA("John Smith", queue); AlunoUSP alunoUSP = new AlunoUSP("Mark Smith", queue); AlunoUnicamp alunoUnicamp = new AlunoUnicamp("Joseph Smith", queue); try { alunoITA.setComportamento( new SafoPreguicoso(alunoITA) ); alunoITA.setComportamento( new Summa(alunoITA) ); alunoUSP.setComportamento( new Burro(alunoUSP) ); alunoUnicamp.setComportamento( new Burro(alunoUnicamp) ); } catch (Exception e) { fail("Não deveria lançar erro!"); } try { alunoITA.setComportamento( new Burro(alunoITA) ); } catch (Exception e) { System.out.println("Iteano naum eh burro!"); } try { alunoUSP.setComportamento( new SafoPreguicoso(alunoUSP) ); } catch (Exception e) { System.out.println("USPeano naum eh safopreguicoso!"); } try { alunoUnicamp.setComportamento( new Summa(alunoUnicamp) ); } catch (Exception e) { System.out.println("Unicampeano naum eh summa!"); } } public void testRelaQueueEhSubclasseDoGenericoQueue() { Queue<Relatorio> q = new RelaQueue(); //propriedade básica do polimorfismo } }
O esquema das Classes compiladas foi:
O resultado de TestAll na Classe de Testes foi:
Ao se fazer testes com interação com o usuário através do método main de Simulator, obtivemos:
O projeto completo do laboratório é Laboratório 2.
Conclusão
A importância deste laboratório foi aplicar conceitos importante de Orientação a Objetos aprendidos em sala de aula. Tais conceitos, que podem ser aplicados em muitas situação, fizeram que o programa ficasse mais flexivel, como no caso dos genéricos. Outro conceito a meu ver extremamente importante usado foi o tratamento de Exceptions. O uso do mesmo torna o programa menos vulnerável a erros cometidos pelo usuário.
A única dificuldade na realização do laboratório foi o uso de genéricos, já que os slides da aula 6 não deixavam muito claro como implementar.
corrigido. Seria melhor extrair o try…catch e usar um só no seu simulador,, mais externo, evitando repetição e separando o tratamento de erros do código. O trecho a melhorar é o abaixo: