Lab2 Thiago Brandão

aluno: Thiago Brandão Damasceno
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 20/08/2008 (4)

Introdução

O segundo laboratório consistiu em acrescentar melhorias ao primeiro laboratório, treinando mais alguns conceitos de programação orientada a objetos, especialmente no que diz respeito a padrões de projeto.
Para tanto, foi utilizado o padrão Strategy para modificar a estrutura relacional entre a classe Aluno e suas subclasses, permitindo que comportamentos sejam atributos modificáveis,além de evitar que código seja repetido nas subclasses correspondentes. Além disso, foi aplicado o conceito de Exceção nos métodos das subclasses de Aluno e criada uma queue de relatórios utilizando um array de genéricos.Uma classe simulador foi adicionada para permitir uma interação mínima com o usuário.

Desenvolvimento

1) Alteração da classe Aluno

A classe Aluno irá somente conter a parte comum a todo aluno. Qualquer comportamento diferente irá ser gerenciado pelo atributo comportamento, fazendo com que o processo de herança da classe Aluno seja mais eficiente, evitando repetição de código desnecessária.

public class Aluno //Aluno deixa de ser classe abstrata
{
 
   private Comportamento comportamento; //ganha novo atributo comportamento
   private int conhecimento;
   private String nome;
   private RelaQueue relaq;
 
   public Aluno(String nm, RelaQueue rq)
   {
       comportamento = new Esforcado(this);
       nome = nm;
       relaq = rq;
   }
 
   public String getNome()
   {
       return nome;
   }
 
   public void fazEEntregaRelatorio()
   {
       float qualidade = (2*this.getDedicacao() + this.getInteligencia())/3;
       float originalidade = (this.getDedicacao() + 2*this.getInteligencia())/3;
       Relatorio rela = new Relatorio(qualidade, originalidade, this);
       relaq.queue(rela);
       conhecimento++;
   }
 
   public int getConhecimento() //retorna conhecimento
   {
       return conhecimento;
   } 
 
   //agora, os métodos getInteligencia() e getDedicacao() são
   //delegados para o objeto comportamento do Aluno
   public float getInteligencia()
   {
       float inteligencia = comportamento.getInteligencia();
 
       return inteligencia;
   }
 
   public float getDedicacao()
   {
       float dedicacao = comportamento.getDedicacao();
 
       return dedicacao;
   }
 
   //será possível modificar o comportamento do aluno
   //o método lança exceção pois existirão subclasses que também
   //lançarão exceções toda vez que se atribuir a um aluno 
   //um determinado comportamento "proibido" 
   public void setComportamento(Comportamento cmpto) throws Exception
   { 
       comportamento = cmpto;
   }
 
   //na classe Professor, a única coisa que muda é que
   //ele coloca o comportamento do aluno ao lado do nome.
   //isso vai ser essencial para analisar exceções
   public Comportamento getComportamento()
   {
       return comportamento; 
   }
 
}

2) Criação da classe Comportamento

A classe que irá sofrer overriding obrigatório de seus métodos será a classe Comportamento. Dela serão derivadas classes que irão diferenciar comportamentos diferentes de alunos, tornando mais modular a relação de aluno com seus atributos.

//a classe abstrata Comportamento irá servir
//de classe delegadora de métodos que manipulam
//características comportamentais como
//inteligencia e dedicação, deixando nítida a separação
//entre o que é comum a cada aluno e o que é particularizável
public abstract class Comportamento
{
 
    //referência ao aluno que contém o objeto da classe Comportamento
    private Aluno aluno; 
 
    public Comportamento(Aluno al)
    {
        aluno = al;
    }
 
    //devem ser definidas nas subclasses de Comportamento 
    abstract float getInteligencia();
    abstract float getDedicacao();
 
}

3) Tipos de comportamento

Abaixo segue os seis tipos de comportamentos definidos para Aluno e suas implementações:

figura1.png

3.1) Classe Burro

public class Burro extends Comportamento
{
 
    private float inteligencia;
    private float dedicacao;
 
    public Burro(Aluno al)
    {
        super(al);
        inteligencia = 0.0f;
        dedicacao = 0.0f;
    }
 
    public float getInteligencia()
    {
        return inteligencia;
    }
 
    public float getDedicacao()
    {
        return dedicacao;
    }
 
}

3.2) Classe Esforcado

public class Esforcado extends Comportamento
{
 
    private float inteligencia;
    private float dedicacao;
 
    public Esforcado(Aluno al)
    {
       super(al); 
       inteligencia = 0.5f;
       dedicacao = 1.0f;
    }
 
    public float getInteligencia()
    {
        return inteligencia;
    }
 
    public float getDedicacao()
    {
        return dedicacao;
    }
 
}

3.3) Classe Imprevisivel

import java.util.*;
 
public class Imprevisivel extends Comportamento
{
 
    public Imprevisivel(Aluno al)
    {
        super(al);
    }
 
    public float getInteligencia() 
    {
        Random generator = new Random();
 
        float r = generator.nextFloat();
 
        return r;
 
    }
 
    public float getDedicacao() 
    {
        Random generator = new Random();
 
        float r = generator.nextFloat();
 
        return r;
 
    }
 
}

3.4) Classe Pemba

import java.util.*;
 
public class Pemba extends Comportamento
{
 
    public Pemba(Aluno al)
    {
        super(al);
    }
 
    public float getInteligencia() 
    {
        Random generator = new Random();
 
        float r = generator.nextFloat();
 
        return r*0.5f;
 
    }
 
    public float getDedicacao() 
    {
        Random generator = new Random();
 
        float r = generator.nextFloat();
 
        return r*0.5f;
 
    }
}

3.5) Classe SafoPreguicoso

import java.util.*;
 
public class SafoPreguicoso extends Comportamento
{
 
    private float inteligencia;
    private float dedicacao;
 
    public SafoPreguicoso(Aluno al)
    {
        super(al);
        inteligencia = 1.0f;
    } 
 
    public float getInteligencia() 
    {
        return inteligencia;
    }
 
    public float getDedicacao() 
    {
        Random generator = new Random();
 
        float r = generator.nextFloat();
 
        return r*0.5f; 
 
    }
}

3.6) Classe Summa

public class Summa extends Comportamento
{
 
    private float inteligencia;
    private float dedicacao;
 
    public Summa(Aluno al)
    {
        super(al);
        inteligencia = 1.0f;
        dedicacao = 1.0f;
    }
 
    public float getInteligencia()
    {
         return inteligencia;
    }
 
    public float getDedicacao()
    {
        return dedicacao;
    }
}

3.7) De que outra maneira poderia ser feito?

A classe Comportamento poderia ter sido implementada como uma interface, de modo que alunos específicos poderiam herdar direto da classe Aluno e implementariam o comportamento no mesmo bloco de código.

4) Tipos de aluno

Agora que a parte comportamental de Aluno foi separada de sua implementação, fica mais fácil criar tipos de Aluno específicos, como por exemplo, de instituições diferentes.

figura2.png

O método setComportamento() poderá jogar uma exceção agora. Toda vez que for criado um aluno do ITA que tenha comportamento Burro ou alunos da USP/Unicamp que sejam SafoPreguicoso ou Summa, irá ser criado um objeto do tipo Exception. Esse objeto obrigará que, no escopo de chamada do método, seja realizado algum tipo de tratamento, como por exemplo, exibir uma mensagem. Será observado que, comportamentos que lançam exceções não são atribuídos aos alunos e estes, portanto, continuam sendo alunos do tipo Esforcado, que é o default.

4.1) Classe AlunoITA

public class AlunoITA extends Aluno
{
 
   public AlunoITA(String nm, RelaQueue rq)
   {
       super(nm, rq);
   }
 
   public void setComportamento(Comportamento cmpto) throws Exception
   {    
        //aluno do ITA não pode ter comportamento de Burro
        if(cmpto instanceof Burro) throw new Exception(); 
        super.setComportamento(cmpto); 
   }
}

4.2) Classe AlunoUSP

public class AlunoUSP extends Aluno
{
 
    public AlunoUSP(String nm, RelaQueue rq)
    {
       super(nm, rq);
    }
 
    public void setComportamento(Comportamento cmpto) throws Exception
    {   
        //aluno da USP não pode ter comportamento de Summa ou SafoPreguicoso
        if((cmpto instanceof Summa) || (cmpto instanceof SafoPreguicoso)) 
           throw new Exception(); 
        super.setComportamento(cmpto); 
    }
}

4.3) Classe AlunoUnicamp

public class AlunoUnicamp extends Aluno
{
    public AlunoUnicamp(String nm, RelaQueue rq)
    {
        super(nm, rq);
    }
 
    public void setComportamento(Comportamento cmpto) throws Exception
    {
        //aluno da Unicamp não pode ter comportamento de Summa ou SafoPreguicoso
        if((cmpto instanceof Summa) || (cmpto instanceof SafoPreguicoso))
           throw new Exception();
        super.setComportamento(cmpto); 
 
    }
 
}

5) Classe Simulador

import java.util.*;
 
//A classe Simulador irá proporcionar uma
//interação mínima do usuário com o programa.
//Foi escolhida a classe Scanner para leitura 
//de dados (feita universalmente como String),
//conversão para inteiros utilizando parser 
//quando necessário e o método System.out.print(ln)
//para imprimir resultados na tela.
 
public class Simulador
{
 
      //para criar um objeto no BlueJ, não pode ser do tipo static 
      public void main() 
      {
 
       //criar todas as variáveis como String evita digitação de tipos incompatíveis e 
       //o problema do \n no buffer de entrada
       String nome; 
       String num_alunos_s;  //numero de alunos
       String age_s;         //idade 
       String tipo_s; 
       String inst_s;        //instituição que estuda
       int tmp;              //variável temporária para realizar loops e decrementos
       int num_alunos; 
       int age;
       RelaQueue queue = new RelaQueue();
       Aluno[] alunoArray = new Aluno[10]; //no máximo dez alunos na fila
       Comportamento cmpto;
       Professor prof = new Professor(queue);
 
       Scanner in = new Scanner(System.in);
 
       //apesar de existir um valor limite para o n° de alunos,
       //será suposto que o usuário irá digitar um número consistente,
       ///isto é, menor ou igual a 10. 
       System.out.print("Digite o número de alunos: ");
       num_alunos_s = in.nextLine();
       System.out.println();
       num_alunos = Integer.parseInt(num_alunos_s);
       tmp = num_alunos;
 
       //loop para num_alunos alunos
       while(tmp > 0) 
       {
 
           System.out.print("Digite o nome do " + (num_alunos - tmp + 1) + "° aluno:");
           nome = in.nextLine();
 
           System.out.print("Digite o nome da instituição em que estuda:");
           inst_s = in.nextLine();
 
           if(inst_s.equals("ITA"))
              alunoArray[num_alunos - tmp] = new AlunoITA(nome, queue);
           else if(inst_s.equals("Unicamp"))
              alunoArray[num_alunos - tmp] = new AlunoUnicamp(nome, queue);
           else if(inst_s.equals("USP"))
              alunoArray[num_alunos - tmp] = new AlunoUSP(nome, queue);
           else
              alunoArray[num_alunos - tmp] = new AlunoUSP(nome, queue); //default
 
           System.out.print("Digite o tipo do aluno:");
           tipo_s = in.nextLine();
           System.out.println();
 
           if(tipo_s.equals("burro"))
              cmpto = new Burro(alunoArray[num_alunos - tmp]);
           else if(tipo_s.equals("esforçado"))
              cmpto = new Esforcado(alunoArray[num_alunos - tmp]);
           else if(tipo_s.equals("imprevisível"))
              cmpto = new Imprevisivel(alunoArray[num_alunos - tmp]);
           else if(tipo_s.equals("pemba"))
              cmpto = new Pemba(alunoArray[num_alunos - tmp]);
           else if(tipo_s.equals("safo preguiçoso"))
              cmpto = new SafoPreguicoso(alunoArray[num_alunos - tmp]);
           else if(tipo_s.equals("summa"))
              cmpto = new Summa(alunoArray[num_alunos - tmp]);
           else
              cmpto = new Esforcado(alunoArray[num_alunos - tmp]); //default caso algum erro aconteça
 
           try
           {
              alunoArray[num_alunos - tmp].setComportamento(cmpto); //pode lançar exceção
           }
           catch(Exception e)
           {
               System.out.println("Ser " + cmpto.getClass().getName().toLowerCase() + 
               " é um comportamento inadequado para " + alunoArray[num_alunos - tmp].getClass().getName());
           }
 
           tmp--;
        }
 
        tmp = num_alunos;
 
        //todos os alunos fazem e entregam os relatórios
        while(tmp > 0)
        {
            alunoArray[num_alunos - tmp].fazEEntregaRelatorio();
            tmp--;
        }
 
        //o professor corrige os relatórios
        prof.corrigirRelatorios();
 
       in.close();            
 
      }
 
}

6) Classe Queue com genéricos: Queue<T>

A criação da classe RelaQueue com genéricos exercita o conceito de genéricos em Java. Agora, qualquer tipo de queue poderá ser chamada, bastando que o parâmetro T seja substituído por uma classe apropriada.

figura6.png
public class Queue<T>
{
    private int inicio;
    private int fim;
    private T[] array;
 
    public Queue()
    {
        inicio = 0;
        fim = 0;
        array = (T[]) new Object[10];
 
        //deve-se evitar criação direta com o tipo T
        //pois a criação de array de genéricos é proibida
        //em Java. A solução escolhida foi criar um array 
        //de Object (pois todas as classes herdam dela)
        //e fazer um casting. Apesar de ser uma operação
        //insegura para o compilador, a solução realiza o pretendido. 
    }
 
    public boolean isEmpty()
    {
        if(inicio == fim)
           return true;
        else
           return false;
    }
 
    public void queue(T obj)
    {
       array[fim] = obj;
       fim = (fim + 1) % 10;
    }
 
    public T dequeue()
    {
        if(isEmpty())
           return null;
        else
        {
            T tmp = array[inicio];
            inicio = (inicio + 1) % 10;
            return tmp;
        }
    }
 
}

Corpo da classe RelaQueue se reduz a passar Relatorio como parâmetro para criar a nova classe:

public class RelaQueue extends Queue<Relatorio>
{
}

Esquema final do programa no BlueJ:

figura7.png

7) Testes

7.1) Teste com o Simulador

O primeiro teste verifica a criação de alunos de ddiferentes instituições e comportamentos. Após a criação, os alunos colocam os relatórios na fila e o professor corrige os relatórios, colocando o nome do aluno (com seu comportamento), ao lado se sua nota.

figura5.png

No segundo teste, tentou-se atribuir comportamentos proibidos aos alunos de instituições diferentes. Como esperado, exceções foram lançadas e mensagens foram mostradas para o usuário, confirmando a operação ilegal. Note que todos os alunos continuam sendo do tipo Esforcado, o que significa que o programa ignorou a tentativa do usuário de atribuição não permitida, tornando o programa mais seguro.

figura8.png

7.2) Teste com a classe Teste

Resultado do teste com a classe Teste:

figura3.png

Notas dos alunos Smith:

figura4.png

Download do projeto completo

Conclusão

A maior dificuldade da execução do laboratório foi a limitação da linguagem Java em lidar com IO de maneira simples e objetiva. O laboratório permitiu aplicar na prática um exemplo de padrão de projeto, o que é importante para estabelecer um contato com programação orientada a objetos da maneira mais logicamente estruturada possível. Foi possível entender também como funciona as exceções em Java e a construção de tipos que guardam características em comum utilizando o conceito de tipos genéricos.

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License