Lab2 Livia

aluno: Nome do Aluno
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 06/08/2008 (2)

Introdução

Este 2o Laboratório foi uma extensão do laboratório anterior, no qual alunos de tipos diferentes (representados por classes herdeiras da classe abstrata "Alunos") faziam relatórios de qualidade condizente com suas características, colocavam todos em uma fila de relatórios que, por sua vez, eram corrigidos por um professor. Realizamos 3 modificações principais neste programa:
1 - A fila de relatórios "RelaQueue" passou a ser a extensão de uma classe "Queue" genérica;
2 - O comportamento de cada aluno passou a ser definido por um objeto da classe "Comportamento" que está ligada de forma única a este aluno e vice-versa. Com isso, "Aluno" deixou de ser uma classe abstrata e suas extensões passaram a ser feitas de acordo com a faculdade na qual estudam. Algumas restrições quanto ao comportamento de cada uma destas classes-filhas de "Aluno" foram implementadas utilizando o conceito de exceções.
3 - Existe uma classe de simulação que interage com o usuário pedindo informações dos alunos que serão instanciados;
Mais detalhes de cada motificação estão na seção "Desenvolvimento" abaixo. As demais características e classes do programa já foram apresentadas no relatório anterior.

Desenvolvimento

1- Classes "Queue" e "RelaQueue"

Uma fila pode ser formada por objetos de diferentes classes. Por isso, é interessante sabermos criar uma classe genérica que implementa a estrutura de dados "fila". Só será definido de quê será a fila no momento de sua instanciação.
Java permite a criação de classes genéricas de maneira simples, como na classe "Queue" usada no programa:

public class Queue <T>
{
    private T[] array;
    final static int ARRAY_LENGHT=10;
    private int inicio;
    private int fim;
 
    public Queue() {   // método construtor que inicia a array e seta os índices "fim" e "inicio" em 0
        array=(T[])new Object[ARRAY_LENGHT];
        inicio=0;
        fim=0;    
    }    
    public void queue(T obj){   // método para empilhar novo objeto
        array[fim]= obj;
        fim=(fim+1)%10;
    }    
    public T dequeue(){   // método para desenpilhar o objeto que está no início da fila
        if(vazia()) return null;
        T obj = array[inicio];
        inicio=(inicio+1)%10;
        return obj;
    }    
    private boolean vazia(){  //método para verificar se a fila está vazia
        if(fim==inicio) return true;
        return false;
    }
}

Note que o tipo "T" é usado nos métodos "void queue(T obj)" e "T dequeue()", para deixar claro que, uma vez definido o tipo "T", só poderemos empilhar e desempilhar objetos deste tipo.
Outro ponto que merece destaque é a definição do vetor "T array[]" no método construtor. Como o compilador não aceita a criação de um vetor de um tipo desconhecido, é criado um vetor de objetos, que é modificado para ser visto como um vetor de tipo "T".

2 - Classes "Comportamento", "Aluno" e herdeiras

Sabemos que existem alunos dos mais diversos comportamentos nas mais diversas faculdades. Por isso, se quiséssemos criar por extensão da classe "Aluno" todas as combinações possíveis de comportamento e faculdade, o número de classes no projeto cresceria muito. Por isso, foi criada a classe abstrata "Comportamento" com os métodos "getInteligencia()" e "getDedicacao", que devem ser sobrescritos em cada uma da extensões desta classe abstrata. Esta classe comportamento possui também uma variável interna do tipo "Aluno" que define a qual aluno este comportamento está associado. A classe "Comportamento" e uma de suas extensões seguem abaixo:

public abstract class Comportamento {
 
    private Aluno aluno;  //Variável que armazena o "dono" do comportamento. Aceita qualquer classe-filha de "Aluno"
 
    public Comportamento(Aluno aluno) {
        this.aluno=aluno;
    }    
    public abstract float getInteligencia();    
    public abstract float getDedicacao();
}
public class SafoPreguicoso extends Comportamento{
 
    public SafoPreguicoso(Aluno aluno) {
        super(aluno);
    }
    public float getInteligencia() {
        return (float)1;
    }
    public float getDedicacao() {
        Random randomGen = new Random();
        float random=randomGen.nextFloat();
        return random*((float)0.5);
    }
}

A classe "Aluno", por sua vez, deixou de ser abstrata e ganhou uma nova variável do tipo "Comportamento", assim como um método para "setComportamento(Comportamento)" para modificá-la. Com isso, os métodos "getInteligencia" e "getDedicação" simplesmente invocam os métodos com mesmo nome do objeto do tipo "Comportamento" associado a cada aluno.
Os trechos do código da classe "Aluno" que foram modificados ao adicionados em relação à classe "Aluno" do lab. anterior seguem abaixo:

public class Aluno {
 
    private int conhecimento;
    ......
 
    public Aluno(String nome, RelaQueue queue ){
        this.nome=nome;
        this.queue=queue;
        conhecimento=0;
        comportamento = new Esforcado(this); //inicialmente, o comportamento de um aluno é sempre do tipo "Esforçado"
    }
    public void fazEEntregaRelatorio(){
//o calculo da qualidade e originalidade do rela é feito invocando os métodos do comportamento que determinam a
//dedicação e a inteligência do aluno
        double qualidade = (2 * comportamento.getDedicacao() + 1 * comportamento.getInteligencia() ) / 3 ;
        double originalidade = (1 * comportamento.getDedicacao() + 2 * comportamento.getInteligencia() ) / 3 ;
        Relatorio rela = new Relatorio((float)qualidade,(float)originalidade,this);
        queue.queue(rela);
        this.conhecimento=this.conhecimento+1;
    }    
    public int getConhecimento(){
        return conhecimento;
    }   
    public float getInteligencia(){
       return this.comportamento.getInteligencia(); 
    }
    public float getDedicacao(){
        return this.comportamento.getDedicacao();
    }
    public void setComportamento(Comportamento comportamento) throws NotCompatibleException{
//Método para modificar o comportamento do aluno. Lança exceção para casos de imcopatiblidade do aluno com 
//o comportamento dado.
        this.comportamento=comportamento;        
    }
   .....
}

As extensões da classe Aluno criadas foram "AlunoUSP", "AlunoITA" e "AlunoUnicamp". A única diferença entre elas é no método sobrescrito "setComportamento", que lança a exceção "NotCompatibleException" para impedir a associação de um comportamento não compatível com o aluno (Um aluno da USP ou Unicamp não pode ser Summa nem Pemba e um iteano não pode ser Burro).
Para ilustrar esta estrutura, segue abaixo o código de "AlunoITA":

public class AlunoITA extends Aluno{
 
    public AlunoITA(String nome, RelaQueue queue) {
        super(nome,queue);
    }    
    @Override
    public void setComportamento(Comportamento comportamento) throws NotCompatibleException {
//Método sobrescrito que lança uma exceção em caso de incompatibilidade aluno-comportamento e, caso
//não haja, chama o método com mesmo nome da classe-mãe.
        if(comportamento instanceof Burro) throw new NotCompatibleException("Burro","ITA");
        super.setComportamento(comportamento);
    }
}

Esta exceção lançada em caso de não compatibilidade é simplismente a extensão da classe "RunTimeException" que avisa, numa JOptionPane, que um dado comportamento e um dado aluno não são compatíveis. Seu código é:

public class NotCompatibleException extends RuntimeException{

    public NotCompatibleException(String comportamento, String facul) {
        JOptionPane.showMessageDialog(null, 
                                      "Comportamento "+comportamento+" não aplicavel a um aluno de "+facul,
                                      "Comportamento nao Compativel",JOptionPane.ERROR_MESSAGE);
    }
}

A janela de aviso criada pelo construtor desta exceção tem a seguinte aparência:

TelaExcecao

3- Classe de Interface com o usuário

É importante criar uma maneira de permitir que o usuário crie um aluno na maniera que quiser, entrando com um nome, uma faculdade e um comportamento. Para isso, optei por uma janela que extende "JFrame" criada a partir das ferramentas que o NetBeans proporciona aos seus usuários. Esta janela, usada para de entrada de dados e botões para visualização, ficou da seguinte forma:

Tela

Cada tela está associada a um professor, uma fila de relas e um array de alunos. Os botões controlam a criação de alunos e suas ações. Seguem abaixo os parâmetros adicionados ao código da tela fornecido pelo NetBeans, o construtor da classe e os métodos acionados com a seleção dos 3 botões da tela:

public class Frame extends javax.swing.JFrame {
 
    private Aluno[] classe; //array com todos os alunos entrados pelo usuario
    private RelaQueue relaqueue; 
    private Professor professor;
    private int numeroAlunos; //variavel que guarda o numero de alunos na classe
    private final int TAMANHO_CLASSE=30;
//variáveis do tipo "final" que associam um número a um comportamento
    private final int TAMANHO_CLASSE=30;
    private final int BURRO=0;
    private final int ESFORCADO=1;
    private final int IMPREVISIVEL=2;
    private final int PEMBA=3;
    private final int SAFOPREGUICOSO=4;
    private final int SUMMA=5;
 
//construtor da Tela
    public Frame() {
        initComponents(); //chama método que desenha componentes na tela como desejado
        numeroAlunos=0;
        classe=new Aluno[TAMANHO_CLASSE];
        relaqueue=new RelaQueue();
        professor=new Professor(relaqueue);
    }
 
/*Método invocado com o acionamento do botão "CriarAluno".
Este método verifica se todos os campos foram preenchidos, cria
um aluno com o nome e a faculdade dada e seta seu comportamento
conforme a escolha do usuário. Caso não haja imcopatibilidade, este
aluno é colocado no array "classe".
*/
private void CriarAluno(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CriarAluno
    if (ComboBoxComportamentos.getSelectedItem()==null || this.ComboBoxFaculs.getSelectedItem()==null||
            this.TextFieldNome.getText()==null)
        throw new CriarAlunoException("Preencha todos os campos!");
    Aluno aluno;
    switch(this.ComboBoxFaculs.getSelectedIndex()){
    case 0: aluno=new AlunoITA(this.TextFieldNome.getText(),relaqueue);break;
    case 1: aluno=new AlunoUSP(this.TextFieldNome.getText(),relaqueue);break;
    case 2: aluno=new AlunoUnicamp(this.TextFieldNome.getText(),relaqueue);break;
    default: throw new CriarAlunoException("ih!");
    }
    try{
        switch(this.ComboBoxComportamentos.getSelectedIndex()){
        case BURRO:aluno.setComportamento(new Burro(aluno));break;
        case PEMBA:aluno.setComportamento(new Pemba(aluno));break;
        case ESFORCADO:aluno.setComportamento(new Esforcado(aluno));break;
        case SAFOPREGUICOSO:aluno.setComportamento(new SafoPreguicoso(aluno));break;
        case SUMMA:aluno.setComportamento(new Summa(aluno));break;
        case IMPREVISIVEL:aluno.setComportamento(new Imprevisivel(aluno));break;
        default: throw new CriarAlunoException("ih!");
        }
    }
    catch(NotCompatibleException ex){
        throw ex;
    }
    classe[numeroAlunos]=aluno;
    numeroAlunos++;     
}
 
/*Método invocado com o acionamento do botão "Listar Alunos".
Ele armazena em um String o nome de todos os alunos inseridos
até então no array "classe" e cria um JOptionPane para mostrar
estes nomes ao usuário.
*/
private void ListarAlunos(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ListarAlunos
    String s="Alunos: \n";
    for(int i=0;i<numeroAlunos;i++)
       s=s+" - Nome: "+classe[i].getNome()+" | Dedicação: "+classe[i].getDedicacao()+ " | Inteligencia: "+
               classe[i].getInteligencia()+"\n";
    JOptionPane.showMessageDialog(null, s,"Alunos Cadastrados",JOptionPane.PLAIN_MESSAGE);    
}
 
/*Método invocado com o acionamento do botão "Fazer, Mandar e Corrigir Relas".
Ele invoca o método "fazEEntregaRelatorio()" de todos os alunos do array e, a seguir, manda o professor
corrigí-los. O método "corrigirRelatorios()" da classe "Professor" mostra em uma JOptionPane as notas.
*/
private void MandarCorrigirRelas(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MandarCorrigirRelas
    for(int i=0;i<numeroAlunos;i++)
        classe[i].fazEEntregaRelatorio();    
    professor.corrigirRelatorios();
}

As telas do tipo JOptionPane de exibição dos alunos e notas são similares à tela abaixo:

TelaExibiçãoNotas

Além da exceção de incompatibilidade, criei também uma exceção similar para evitar que o usuário tente criar um aluno sem que todos os campos da tela de interface tenha sido preenchidos. Esta exceção será captada no momento da criação de um aluno. O código e a aparência da JOptionPane criada pelo método construtor desta classe de exceção seguem abaixo:

public class CriarAlunoException extends RuntimeException{
 
    public CriarAlunoException(String message) {
        JOptionPane.showMessageDialog(null, message,
        "Erro ao criar Aluno",JOptionPane.ERROR_MESSAGE);
    }
}
TelaExcecao2

Resultados dos Testes

Foi criada uma classe de testes idêntica à passada nas instruções do 2o Laboratório. Os testes foram bem sucedidos, como mostra a tela abaixo:

ResultadoTestes

Projeto completo no BlueJ

O Projeto no BlueJ tem a seguinte estrutura:

ClassesProjetoBlueJ

O excesso de linhas entre as classes, que indica ligação de quase todas com quase todas as outras classes, mostra que talvez esta não seja a estrutura ideal em termos de organização e facilidade de atualização. Os padrões de projeto com os quais teremos contado em aula de teoria talvez ajudem na estruturação de projetos futuros.

O arquivo com o projeto completo segue em anexo. Ele pode ser aberto tanto no NetBeans como no BlueJ.
Projeto

Conclusão

Este lab foi interessante, pois nos permitiu aplicar diversos conceitos aprendidos em aula de forma simples e prática, como o uso de classes genéricas, tratamento de exceções e a aplicação de estratégias para evitar explosão de classes-filhas.
Foi interessante, também, criar uma interface com o usuário mais "amigável" do que uma simples tela de comando. Para isso, o NetBeans foi de extrema relevância, pois ele permite a criação de telas de forma manual e análise do código gerado pelo IDE. Com isso, fiquei conhecendo mais a bliblioteca "swing" de Java.
O uso do BlueJ foi desnecessário, somente para cumprir as exigências estabelecidas para os labs.

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