Orientação a Objeto - Interfaces e Polimorfismo

Objetivos da seção

Um Sistema Simples de Manipulação de Correio Eletrônico: Um Exercíco na Modularização de um Programa

Sessão típica de uso do sistema que queremos implementar

C:\...\src>java -classpath .;packagep1\p1.jar Correio1 jacques
---------------------------------------------------------------------
Nao ha mensagem.
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? en
Para quem? ana
Assunto? te amo, minha linda!
Conteudo da mensagem? (. para terminar)
Ana,
Voce sabia que eh o eterno amor de minha vida?
Beijos do fofo!

fofo
.
---------------------------------------------------------------------
Nao ha mensagem.
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? en
Para quem? ana
Assunto? amor, novamente
Conteudo da mensagem? (. para terminar)
Nao tendo recebido resposta a minha mensagem anterior,
eu gostaria de reafirmar tudo que ai foi dito, ta?

o fofo
.
---------------------------------------------------------------------
Nao ha mensagem.
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? q
Salvar CaixaPostal? s

C:\...\src>java -classpath .;packagep1\p1.jar Correio1 ana
---------------------------------------------------------------------
  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 15:52 te amo, minha linda!
    2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? exi
De: jacques
Data: 29/06/2001 15:52
Assunto: te amo, minha linda!
Ana,
Voce sabia que eh o eterno amor de minha vida?
Beijos do fofo!

fofo

---------------------------------------------------------------------
  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 15:52 te amo, minha linda!
    2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? exc
---------------------------------------------------------------------
  Num Remetente    Data             Assunto
>X  1 jacques      29/06/2001 15:52 te amo, minha linda!
    2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? +
---------------------------------------------------------------------
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 15:52 te amo, minha linda!
>   2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? exi
De: jacques
Data: 29/06/2001 15:53
Assunto: amor, novamente
Nao tendo recebido resposta a minha mensagem anterior,
eu gostaria de reafirmar tudo que ai foi dito, ta?

o fofo

---------------------------------------------------------------------
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 15:52 te amo, minha linda!
>   2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? exc
---------------------------------------------------------------------
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 15:52 te amo, minha linda!
>X  2 jacques      29/06/2001 15:53 amor, novamente
---------------------------------------------------------------------
exibir, enviar, excluir, +, -, quit? q
Salvar CaixaPostal? s

O projeto básico do sistema

O programa principal

/*
 * Correio Eletrônico simples. Programa principal.
 */
import p1.aplic.correio.*;

public class Correio1 {
    public static void main(String[] args) {
        if(args.length != 1) {
            System.err.println("Sintaxe: java Correio1 nome");
            System.exit(1);
        }
        CorreioIU1 ciu = new CorreioIU1(args[0]);
        ciu.interfaceComUsuário();
    }
}

A classe CorreioIU1

// interface com o usuário para um sisteminha de correio eletrônico
public class CorreioIU1 {
  private CaixaPostal caixa;

  public CorreioIU1(String titular) {
    // construtor para manipular a caixa postal de "titular"
  }

  public void interfaceComUsuário() {
    loop de interpretação de comandos {
      mostrar um resumo da caixa postal para o usuário
      ler o comando
      se comando for "exibir"
        exibir a mensagem
      se comando for "enviar"
        obtem dados (destinatário, assunto, texto da mensagem)
        criar uma nova mensagem com esses dados
        armazenar a mensagem na caixa postal do destinatário
      se comando for "excluir"
        mandar excluir a mensagem corrente
      se comando for "+"
        avançar para a próxima mensagem
      se comando for "-"
        recuar para a mensagem anterior
      se comando for "quit"
        salvar a caixa postal se o usuário quiser e cair fora
    }
  }
}
// interface com o usuário para um sisteminha de correio eletrônico
// a classe ainda não faz parte do package p1.aplic.correio
import p1.aplic.correio.*;
import p1.io.*;

public class CorreioIUTemp1 {
  private CaixaPostal caixa;

  public CorreioIUTemp1(String titular) {
    caixa = new CaixaPostal(titular);
  }

  public void interfaceComUsuário() {
    while(true) {
      System.out.println( "Resumo da caixa postal para o usuario");
      String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
      if(cmd.startsWith("exi")) {
        System.out.println("Exibicao de mensagem");
      } else if(cmd.startsWith("en")) {
        // obtem dados (destinatário, assunto, texto da mensagem)
        // criar uma nova mensagem com esses dados
        // armazenar a mensagem na caixa postal do destinatário
        System.out.println("Envio de nova mensagem");
      } else if(cmd.startsWith("exc")) {
        System.out.println("Exclusao de mensagem");
      } else if(cmd.startsWith("+")) {
        System.out.println("Avanca para proxima mensagem");
      } else if(cmd.startsWith("-")) {
        System.out.println("Recua para mensagem anterior");
      } else if(cmd.startsWith("q")) {
        cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
        if(cmd.startsWith("s")) {
          System.out.println("Salvamento da caixa postal");
        }
        break;
      } else {
        System.out.println("Comando <" + cmd + "> desconhecido");
      }
    }
  }

  // um mainzinho para testar
  public static void main(String[] args) {
    if(args.length != 1) {
      System.err.println("Sintaxe: java CorreioIUTemp1 nome");
        System.exit(1);
    }
    CorreioIUTemp1 ciu = new CorreioIUTemp1(args[0]);
    ciu.interfaceComUsuário();
  }
}
C:\...\src>java -classpath .;packagep1\p1.jar CorreioIUTemp1 jacques
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? exi
Exibicao de mensagem
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? en
Envio de nova mensagem
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? exc
Exclusao de mensagem
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? +
Avanca para proxima mensagem
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? -
Recua para mensagem anterior
Resumo da caixa postal para o usuario
exibir, enviar, excluir, +, -, quit? alo
Comando <alo> desconhecido
exibir, enviar, excluir, +, -, quit? q
Salvar CaixaPostal? s
Salvamento da caixa postal
// interface com o usuário para um sisteminha de correio eletrônico
// a classe ainda não faz parte do package p1.aplic.correio
import p1.aplic.correio.*;
import p1.io.*;

public class CorreioIUTemp2 {
  private CaixaPostal caixa;

  public CorreioIUTemp2(String titular) {
    caixa = new CaixaPostal(titular);
  }

  public void interfaceComUsuário() {
    while(true) {
      System.out.println( "Resumo da caixa postal para o usuario");
      String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
      if(cmd.startsWith("exi")) {
        Mensagem m = caixa.mensagemCorrente();
        if(m != null) {
          m.exibir();
        }
      } else if(cmd.startsWith("en")) {
        // obtem dados (destinatário, assunto, texto da mensagem)
        // criar uma nova mensagem com esses dados
        // armazenar a mensagem na caixa postal do destinatário
        System.out.println("Envio de nova mensagem");
      } else if(cmd.startsWith("exc")) {
        caixa.excluir();
      } else if(cmd.startsWith("+")) {
        caixa.avançar();
      } else if(cmd.startsWith("-")) {
        caixa.recuar();
      } else if(cmd.startsWith("q")) {
        cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
        if(cmd.startsWith("s")) {
          caixa.salvar();
        }
        break;
      } else {
        System.out.println("Comando <" + cmd + "> desconhecido");
      }
    }
  }

  // um mainzinho para testar
  public static void main(String[] args) {
    if(args.length != 1) {
      System.err.println("Sintaxe: java CorreioIUTemp2 nome");
      System.exit(1);
    }
    CorreioIUTemp2 ciu = new CorreioIUTemp2(args[0]);
    ciu.interfaceComUsuário();
  }
}
// interface com o usuário para um sisteminha de correio eletrônico
// a classe ainda não faz parte do package p1.aplic.correio
import p1.aplic.correio.*;
import p1.io.*;
import java.util.*;

public class CorreioIUTemp3 {
  private CaixaPostal caixa;

  public CorreioIUTemp3(String titular) {
    caixa = new CaixaPostal(titular);
  }

  public void interfaceComUsuário() {
    while(true) {
      mostraResumoCaixaPostal(caixa);
      String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
      if(cmd.startsWith("exi")) {
        Mensagem m = caixa.mensagemCorrente();
        if(m != null) {
          m.exibir();
        }
      } else if(cmd.startsWith("en")) {
        // obtem dados (destinatário, assunto, texto da mensagem)
        // criar uma nova mensagem com esses dados
        // armazenar a mensagem na caixa postal do destinatário
        System.out.println("Envio de nova mensagem");
      } else if(cmd.startsWith("exc")) {
        caixa.excluir();
      } else if(cmd.startsWith("+")) {
        caixa.avançar();
      } else if(cmd.startsWith("-")) {
        caixa.recuar();
      } else if(cmd.startsWith("q")) {
        cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
        if(cmd.startsWith("s")) {
          caixa.salvar();
        }
        break;
      } else {
        System.out.println("Comando <" + cmd + "> desconhecido");
      }
    }
  }

  // Observe que este método *não* é public
  void mostraResumoCaixaPostal(CaixaPostal caixa) {
   final String separador = "---------------------------------------------------------------------";
   Iterator it = caixa.iterator();
    if(!it.hasNext()) {
      System.out.println(separador);
      System.out.println("Nao ha mensagem.");
      System.out.println(separador);
      return;
    }
    int numMensagem = 1;
    System.out.println(separador);
    while(it.hasNext()) {
      Mensagem m = (Mensagem)it.next();
      String cursor = " ";
      if(m == caixa.mensagemCorrente()) {
        cursor = ">";
      }
      System.out.println(cursor + numMensagem +
                         " Rem: " + m.getRemetente() +
                         " Data: " + m.getDataEnvio().DDMMAAAAHHMM() +
                         " Ass: " + m.getAssunto());
      numMensagem++;
    }
    System.out.println(separador);
  }

  // um mainzinho para testar
  public static void main(String[] args) {
    if(args.length != 1) {
      System.err.println("Sintaxe: java CorreioIUTemp3 nome");
      System.exit(1);
    }
    CorreioIUTemp3 ciu = new CorreioIUTemp3(args[0]);
    ciu.interfaceComUsuário();
  }
}
// interface com o usuário para um sisteminha de correio eletrônico
// a classe ainda não faz parte do package p1.aplic.correio
import p1.aplic.correio.*;
import p1.io.*;
import java.util.*;

public class CorreioIUTemp4 {
  private CaixaPostal caixa;

  public CorreioIUTemp4(String titular) {
    caixa = new CaixaPostal(titular);
  }

  public void interfaceComUsuário() {
    while(true) {
      mostraResumoCaixaPostal(caixa);
      String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
      if(cmd.startsWith("exi")) {
        Mensagem m = caixa.mensagemCorrente();
        if(m != null) {
          m.exibir();
        }
      } else if(cmd.startsWith("en")) {
        String destinatário = obtemUmaLinha("Para quem? ");
        String assunto = obtemUmaLinha("Assunto? ");
        String conteúdo = obtemVáriasLinhas("Conteudo da mensagem? (. para terminar) ");
        enviarMensagem(caixa.getTitular(), destinatário, assunto, conteúdo);
      } else if(cmd.startsWith("exc")) {
        caixa.excluir();
      } else if(cmd.startsWith("+")) {
        caixa.avançar();
      } else if(cmd.startsWith("-")) {
        caixa.recuar();
      } else if(cmd.startsWith("q")) {
        cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
        if(cmd.startsWith("s")) {
          caixa.salvar();
        }
        break;
      } else {
        System.out.println("Comando <" + cmd + "> desconhecido");
      }
    }
  }

  // Observe que este método *não* é public
  void mostraResumoCaixaPostal(CaixaPostal caixa) {
    Iterator it = caixa.iterator();
    if(!it.hasNext()) {
      System.out.println("Nao ha mensagem.");
      return;
    }
    int numMensagem = 1;
    while(it.hasNext()) {
      Mensagem m = (Mensagem)it.next();
      String cursor = " ";
      if(m == caixa.mensagemCorrente()) {
        cursor = ">";
      }
      System.out.println(cursor + numMensagem +
                         " Rem: " + m.getRemetente() +
                         " Data: " + m.getDataEnvio().DDMMAAAAHHMM() +
                         " Ass: " + m.getAssunto());
      numMensagem++;
    }
  }

  // Observe que este método *não* é public
  String obtemUmaLinha(String prompt) {
    String linha;
    while((linha = Entrada.in.lerLinha(prompt)).equals("")) {
      System.out.println("Favor fornecer alguma informacao");
    }
    return linha;
  }

  /** Método auxiliar para obter várias linhas da entrada padrão.
   * O final da entrada é indicado digitando "." sozinho no início
   * de uma linha.
   * @param prompt O prompt a exibir ao usuário antes de ler a informação.
   * @return As linhas lida, como string único. As linhas são separadas
   * por um caractere de separação de linha apropriado.
   */
  // Observe que este método *não* é public
  String obtemVáriasLinhas(String prompt) {
    String resposta = "";
    String separador = System.getProperty("line.separator");
    String linha;
    System.out.println(prompt);
    while(!(linha = Entrada.in.lerLinha("")).equals(".")) {
      resposta += linha + separador;
    }
    return resposta;
  }

  /**
   * Envia uma mensagem de correio eletrônico para um destinatário.
   * @param remetente O remetente da mensagem.
   * @param destinatário O destinatário da mensagem.
   * @param assunto O assunto da mensagem.
   * @param conteúdo O conteúdo da mensagem, podendo conter várias linhas de texto.
   */
  // Observe que este método *não* é public
  void enviarMensagem(String remetente, String destinatário, String assunto, String conteúdo) {
    CaixaPostal caixaDestino = new CaixaPostal(destinatário);
    caixaDestino.inserir(new Mensagem(remetente, assunto, conteúdo));
    caixaDestino.salvar();
  }
  // um mainzinho para testar
  public static void main(String[] args) {
    if(args.length != 1) {
      System.err.println("Sintaxe: java CorreioIUTemp4 nome");
      System.exit(1);
    }
    CorreioIUTemp4 ciu = new CorreioIUTemp4(args[0]);
    ciu.interfaceComUsuário();
  }
}
// ***************************************
// ATENÇÃO: CÓDIGO FEIO à FRENTE!!!!!!!!!!
// ***************************************
// interface com o usuário para um sisteminha de correio eletrônico
// a classe ainda não faz parte do package p1.aplic.correio
import p1.aplic.correio.*;
import p1.io.*;
import java.util.*;

public class CorreioIUTemp5 {
  private CaixaPostal caixa;

  public CorreioIUTemp5(String titular) {
    caixa = new CaixaPostal(titular);
  }

  public void interfaceComUsuário() {
    while(true) {
      Iterator it = caixa.iterator();
      if(!it.hasNext()) {
        System.out.println("Nao ha mensagem.");
        return;
      }
      int numMensagem = 1;
      while(it.hasNext()) {
        Mensagem m = (Mensagem)it.next();
        String cursor = " ";
        if(m == caixa.mensagemCorrente()) {
          cursor = ">";
        }
        System.out.println(cursor + numMensagem +
                          " Rem: " + m.getRemetente() +
                          " Data: " + m.getDataEnvio().DDMMAAAAHHMM() +
                          " Ass: " + m.getAssunto());
        numMensagem++;
      }
      String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
      if(cmd.startsWith("exi")) {
        Mensagem m = caixa.mensagemCorrente();
        if(m != null) {
          m.exibir();
        }
      } else if(cmd.startsWith("en")) {
        String destinatário;
        while((destinatário = Entrada.in.lerLinha("Para quem? ")).equals("")) {
          System.out.println("Favor fornecer alguma informacao");
        }
        String assunto;
        while((assunto = Entrada.in.lerLinha("Assunto? ")).equals("")) {
          System.out.println("Favor fornecer alguma informacao");
        }
        String conteúdo = "";
        String separador = System.getProperty("line.separator");
        String linha;
        System.out.println("Conteudo da mensagem? (. para terminar) ");
        while(!(linha = Entrada.in.lerLinha("")).equals(".")) {
          conteúdo += linha + separador;
        }
        CaixaPostal caixaDestino = new CaixaPostal(destinatário);
        caixaDestino.inserir(new Mensagem(caixa.getTitular(), assunto, conteúdo));
        caixaDestino.salvar();
      } else if(cmd.startsWith("exc")) {
        caixa.excluir();
      } else if(cmd.startsWith("+")) {
        caixa.avançar();
      } else if(cmd.startsWith("-")) {
        caixa.recuar();
      } else if(cmd.startsWith("q")) {
        cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
        if(cmd.startsWith("s")) {
          caixa.salvar();
        }
        break;
      } else {
        System.out.println("Comando <" + cmd + "> desconhecido");
      }
    }
  }

  // um mainzinho para testar
  public static void main(String[] args) {
    if(args.length != 1) {
      System.err.println("Sintaxe: java CorreioIUTemp5 nome");
      System.exit(1);
    }
    CorreioIUTemp5 ciu = new CorreioIUTemp5(args[0]);
    ciu.interfaceComUsuário();
  }
}
/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */
package p1.aplic.correio;

import p1.io.*;
import p1.util.*;
import java.util.*;

/**
 * Classe que implementa uma interface simples (a caractere)
 * de manipulação de mensagens de correio eletrônico.
 * <p>
 * O programa manipula uma caixa postal de mensagens de correio eletrônico.
 * O funcionamento da interface é como segue. Um objeto dessa
 * classe deve ser criado com um argumento especificando o titular da caixa postal
 * a ser manipulada. Ao chamar o método principal (interfaceComUsuário()),
 * o conteúdo da caixa postal pode ser manipulado e novas mensagens podem ser enviadas.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class CorreioIU1 {
    private CaixaPostal caixa;

    /**
     * Construtor de uma interface com o usuário para manipular
     * uma caixa postal de correio eletrônico.
     * @param titular O titular da caixa postal que se deseja manipular.
     */
    public CorreioIU1(String titular) {
        caixa = new CaixaPostal(titular);
    }

    /**
     * Interface com o usuário para a manipulação de caixa postal.
     * A interface consiste basicamente de um laço de interpretação de comandos.
     * O conteúdo da caixa postal é mostrado na tela e um menu de comandos
     * é exibido. Os comandos disponíveis são:
     * <p><strong>exibir</strong>: exibe a mensagem corrente.
     * <p><strong>enviar</strong>: envia uma nova mensagem de correio.
     * Neste caso, deve-se especificar ainda o destinatário, o assunto e
     * o conteúdo da mensagem propriamente dita. O remetente será o titular da caixa postal.
     * <p><strong>excluir</strong>: marca a mensagem corrente para exclusão. Chamamos isso
     * de <strong>exclusão lógica</strong>. A exclusão em sí (física)
     * é feita ao salvar a caixa postal no final (vide o comando "quit").
     * <p><strong>+</strong>: avança para a próxima mensagem.
     * <p><strong>-</strong>: recua para a mensagem anterior.
     * <p><strong>quit</strong>: encerra a manipulação da caixa postal. Pede-se neste momento
     * se a caixa postal deve ser salva em disco ou não. Responda com 's' ou 'n'.
     * <p>Os comandos podem ser digitados de forma abreviada, desde que um número
     * suficiente de letras seja informado. Por exemplo, basta digitar "en" para
     * enviar uma mensagem nova. Digitar "ex" não é suficiente, pois há dois comandos começando
     * com "ex". Deve-se digitar pelo menos "exc" (excluir) ou "exi" (exibir).
     */
    public void interfaceComUsuário() {
        while(true) {
            mostraResumoCaixaPostal(caixa);
            String cmd = Entrada.in.lerLinha("exibir, enviar, excluir, +, -, quit? ");
            if(cmd.startsWith("exi")) {
                Mensagem m = caixa.mensagemCorrente();
                if(m != null) {
                    m.exibir();
                }
            } else if(cmd.startsWith("en")) {
                String destinatário = obtemUmaLinha("Para quem? ");
                String assunto = obtemUmaLinha("Assunto? ");
                String conteúdo = obtemVáriasLinhas("Conteudo da mensagem? (. para terminar) ");
                enviarMensagem(caixa.getTitular(), destinatário, assunto, conteúdo);
            } else if(cmd.startsWith("exc")) {
                caixa.excluir();
            } else if(cmd.startsWith("+")) {
                caixa.avançar();
            } else if(cmd.startsWith("-")) {
                caixa.recuar();
            } else if(cmd.startsWith("q")) {
                cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
                if(cmd.startsWith("s")) {
                    caixa.salvar();
                }
                break;
            } else {
                System.out.println("Comando <" + cmd + "> desconhecido");
            }
        }
    }

    /**
     * Exibe na saída padrão um resumo da mensagens presentes na caixa postal.
     * @param caixa A caixa postal a ser exibida
     */
    // Observe que este método *não* é public
    private void mostraResumoCaixaPostal(CaixaPostal caixa) {
        Iterator it = caixa.iterator();
        if(!it.hasNext()) {
            System.out.println("Nao ha mensagem.");
            return;
        }
        // -16.16s significa um string (s) alinhado à esquerda (-)
        // com um mínimo de 16 caracteres e um máximo de 16 caracteres
        Formata f1 = new Formata("%-16.16s");
        Formata f2 = new Formata("%-40.40s");
        Formata f3 = new Formata("%3d");
        Formata f4 = new Formata("%-12.12s");
        System.out.println("  Num " + f4.form("Remetente") +
                           " " + f1.form("Data") +
                           " " + f2.form("Assunto"));
        int numMensagem = 1;
        while(it.hasNext()) {
            Mensagem m = (Mensagem)it.next();
            String cursor = " ";
            if(m == caixa.mensagemCorrente()) {
                cursor = ">";
            }
            String estado = m.isExcluída() ? "X" : " ";
            System.out.println(cursor + estado +
                                f3.form(numMensagem) + " " +
                                f4.form(m.getRemetente()) + " " +
                                f1.form(m.getDataEnvio().DDMMAAAAHHMM()) + " " +
                                f2.form(m.getAssunto()));
            numMensagem++;
        }
    }

    /** Método auxiliar para obter uma linha da entrada padrão, tendo
     * o cuidado de não aceitar uma linha vazia.
     * @param prompt O prompt a exibir ao usuário antes de ler a informação.
     * @return A linha lida.
     */
    // Observe que este método *não* é public
    private String obtemUmaLinha(String prompt) {
        String linha;
        while((linha = Entrada.in.lerLinha(prompt)).equals("")) {
            System.out.println("Favor fornecer alguma informacao");
        }
        return linha;
    }

    /** Método auxiliar para obter várias linhas da entrada padrão.
     * O final da entrada é indicado digitando "." sozinho no início
     * de uma linha.
     * @param prompt O prompt a exibir ao usuário antes de ler a informação.
     * @return As linhas lida, como string único. As linhas são separadas
     * por um caractere de separação de linha apropriado.
     */
    // Observe que este método *não* é public
    private String obtemVáriasLinhas(String prompt) {
        String resposta = "";
        String separador = System.getProperty("line.separator");
        String linha;
        System.out.println(prompt);
        while(!(linha = Entrada.in.lerLinha("")).equals(".")) {
            resposta += linha + separador;
        }
        return resposta;
    }

    /**
     * Envia uma mensagem de correio eletrônico para um destinatário.
     * @param remetente O remetente da mensagem.
     * @param destinatário O destinatário da mensagem.
     * @param assunto O assunto da mensagem.
     * @param conteúdo O conteúdo da mensagem, podendo conter várias linhas de texto.
     */
    // Observe que este método *não* é public
    private void enviarMensagem(String remetente, String destinatário, String assunto, String conteúdo) {
        CaixaPostal caixaDestino = new CaixaPostal(destinatário);
        caixaDestino.inserir(new Mensagem(remetente, assunto, conteúdo));
        caixaDestino.salvar();
    }
}

A classe Mensagem

/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */

import p1.aplic.geral.*;
import java.io.*;

/**
 * Classe que representa uma mensagem normal de correio eletronico.
 *
 * Uma mensagem contém um remetente, um assunto uma data de envio e algum conteúdo.
 * O conteúdo depende do tipo exato de mensagem (textual, áudio).
 * Uma mensagem pode ser exibida (lida) e marcada para exclusão.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class Mensagem {
    private static final int LIDA = 0x1;
    private static final int EXCLUÍDA = 0x2;
    private static final int NOVA = ~(LIDA | EXCLUÍDA);

    private String  remetente;
    private String  assunto;
    private String  conteúdo;
    private Data    dataEnvio;
    private int     estado;

    public Mensagem(String remetente, String assunto, String conteúdo) {
        this.remetente = remetente;
        this.assunto = assunto;
        this.conteúdo = conteúdo;
        dataEnvio = new Data();
        estado = NOVA;
    }

    /**
     * Recupera o remetente da mensagem
     * @return O remetente da mensagem
     */
    public String getRemetente() {
        return remetente;
    }

    /**
     * Recupera o assunto da mensagem
     * @return O assunto da mensagem
     */
    public String getAssunto() {
        return assunto;
    }

    /**
     * Recupera o conteúdo da mensagem
     * @return O conteúdo da mensagem
     */
    public String getConteúdo() {
        return conteúdo;
    }

    /**
     * Recupera a data de envio da mensagem
     * @return A data de envio da mensagem
     */
    public Data getDataEnvio() {
        return dataEnvio;
    }

    /**
     * Informa se a mensagem foi lida ou não
     * @return true se a mensagem foi lida, false caso contrário
     */
    public boolean isLida() {
        return (estado & LIDA) == LIDA;
    }

    /**
     * Informa se a mensagem foi excluída ou não
     * @return true se a mensagem foi excluída, false caso contrário
     */
    public boolean isExcluída() {
        return (estado & EXCLUÍDA) == EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como excluída.
     * A exclusão deve ser feita pela coleção que armazena as mensagens.
     * Um exemplo de tal coleção é CaixaPostal.
     */
    public void excluir() {
        estado |= EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não excluída.
     */
    public void marcarNãoExcluída() {
        estado &= ~EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não lida.
     */
    public void marcarNãoLida() {
        estado &= ~LIDA;
    }

    /**
     * Testa a igualdade de um objeto com esta mensagem.
     * @param objeto O objeto a comparar com esta mensagem.
     * @return true se o objeto for igual a esta mensagem, false caso contrário.
     */
    public boolean equals(Object objeto) {
        if(! (objeto instanceof Mensagem)) {
            return false;
        }
        Mensagem outra = (Mensagem)objeto;
        return getRemetente().equals(outra.getRemetente())
                && getAssunto().equals(outra.getAssunto())
                && getConteúdo().equals(outra.getConteúdo());
    }

    /**
     * Exibir a mensagem. Os dados da mensagem são apresentados na saída padrão.
     * Após este método, a mensagem é considerada "lida".
     */
    public void exibir() {
        System.out.println("De: " + remetente);
        System.out.println("Data: " + dataEnvio.DDMMAAAAHHMM());
        System.out.println("Assunto: " + assunto);
        System.out.println(conteúdo);
        estado |= LIDA;
    }

    /**
     * Forneça uma representação da mensagem como String
     * @return A representação da mensagem como String.
     */
    public String toString() {
        return "Remetente: " + remetente +
               ", Data: " + dataEnvio.DDMMAAAAHHMM() +
               ", Assunto: " + assunto +
               ", Conteúdo: " + conteúdo;
    }
}

A classe CaixaPostal

/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */
package p1.aplic.correio;

import java.io.*;
import java.util.*;

/**
 * Classe que representa uma caixa de mensagens de correio eletronico.
 * Uma caixa pode conter várias mensagens.
 * Uma caixa pertence a um "titular".
 * <p>A caixa inclui um "cursor" de mensagem. Isto é, existe
 * o conceito de "mensagem corrente" e pode-se avançar e recuar
 * na lista de mensagens (mudando assim a mensagem corrente).
 * <p>Algumas operações podem ser aplicadas à mensagem corrente: excluir, por exemplo.
 * Outras operações se aplicam à caixa como um todo (salvar, removeCaixaPostal).
 * <p>A caixa postal é salva em disco com a operação salvar.
 * Ao criar uma caixa postal, caso exista uma cópia em disco, a caixa
 * é inicializada com as mensagens que estão no disco.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.1
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class CaixaPostal implements Serializable {
  static final long serialVersionUID = 7121517428757951951L;
  private List mensagens;
  private int índiceMensagemCorrente;
  private String titular;

  /**
   * Construção de uma CaixaPostal anônima (sem titular).
   */
  public CaixaPostal() {
    this("");
  }

  /**
   * Construção de uma Caixa Postal
   * Caso haja uma cópia da caixa postal deste titular em disco,
   * as mensagens em disco são carregados na caixa postal sendo criada.
   * No início, a mensagem corrente será a primeira mensagem da caixa.
   * @param titular O titular da caixa postal.
   */
  public CaixaPostal(String titular) {
    this.titular = titular;
    ObjectInputStream in = null;
    try {
      try {
        in = new ObjectInputStream(new FileInputStream(getNomeArquivo()));
        mensagens = (List)in.readObject();
        in.close();
      } catch( FileNotFoundException e ) {
        // nao achar o arquivo significa que estamos começando do zero
        mensagens = new ArrayList();
      }
    } catch(Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    índiceMensagemCorrente = Math.min(0, mensagens.size()-1);
  }

  protected String getNomeArquivo() {
    return titular + ".correio";
  }
  /**
   * Recupera o titular da caixa postal
   * @return O titular da caixa postal.
   */
  public String getTitular() {
    return titular;
  }

  /**
   * Recupera o número de mensagens na caixa postal
   * @return O número de mensagens na caixa postal
   */
  public int númeroDeMensagens() {
    return mensagens.size();
  }

  /**
   * Insira uma nova mensagem no final da caixa postal
   * @param m A Mensagem sendo inserida.
   */
  public void inserir(Mensagem m) {
    mensagens.add(m);
    índiceMensagemCorrente = Math.max(índiceMensagemCorrente, 0);
  }

  /**
   * Recupera a mensagem corrente.
   * <p>A caixa inclui um "cursor" de mensagem. Isto é, existe
   * o conceito de "mensagem corrente" e pode-se avançar e recuar
   * na lista de mensagens (mudando assim a mensagem corrente).
   * @return A mensagem corrente.
   */
  public Mensagem mensagemCorrente() {
    return índiceMensagemCorrente >= 0 ? (Mensagem)mensagens.get(índiceMensagemCorrente) : null;
  }

  /**
   * Avançar o cursor da caixa postal. A mensagem corrente passa a ser a próxima,
   * caso haja. Se a mensagem corrente for a última da caixa postal, não há mudança.

   */
  public void avançar() {
    índiceMensagemCorrente++;
    índiceMensagemCorrente = Math.min(índiceMensagemCorrente, mensagens.size()-1);
  }

  /**
   * Recuar o cursor da caixa postal. A mensagem corrente passa a ser a anterior,
   * caso haja. Se a mensagem corrente for a primeira da caixa postal, não há mudança.
   */
  public void recuar() {
    índiceMensagemCorrente--;
    índiceMensagemCorrente = Math.max(índiceMensagemCorrente, 0);
  }

  /**
   * Forneça um iterador para as mensagens da caixa postal.
   * @return O iterador de mensagens.
   */
  public Iterator iterator() {
    return mensagens.iterator();
  }

  /**
   * Excluir a mensagem Corrente da caixa postal.
   * A exclusão é apenas lógica. A mensagem está marcada para ser excluída
   * mas só é, de fato, excluída ao salvar a caixa postal.
   * @return true, se houve mensagem excluída, false caso contrário (caixa vazia)
   */
  public boolean excluir() {
    if(índiceMensagemCorrente >= 0 && índiceMensagemCorrente < mensagens.size()) {
      mensagemCorrente().excluir();
      índiceMensagemCorrente = Math.min(índiceMensagemCorrente, mensagens.size()-1);
      return true;
    } else {
      return false;
    }
  }

  /**
   * Salvar a caixa postal em disco.
   * Neste momento, as mensagens marcadas para exclusão são removidas
   * (isto é, não são gravadas em disco)
   */
  public void salvar() {
    // primeiro, remover as mensagens excluídas
    Iterator it = iterator();
    while(it.hasNext()) {
      Mensagem m = (Mensagem)it.next();
      if(m.isExcluída()) {
        it.remove();
      }
    }
    ObjectOutputStream out = null;
    try {
      try {
        out = new ObjectOutputStream(new FileOutputStream(getNomeArquivo()));
      } catch(FileNotFoundException e) {
        System.err.println("Nao pode criar " + getNomeArquivo());
        System.exit(1);
      }
      out.writeObject(mensagens);
      out.close();
    } catch(IOException e) {
      System.err.println(e);
      System.exit(1);
    }
    índiceMensagemCorrente = Math.min(índiceMensagemCorrente, mensagens.size()-1);
  }

  /**
   * Remove uma caixa postal armazenada em disco.
   * @param titular O titular da caixa postal a ser removida.
   */
  public static void removeCaixaPostal(String titular) {
    File f = new File(titular + ".correio");
    try {
      f.delete();
    } catch(Exception e) {}
  }
}

Manipulando outros tipos de mensagens: Interfaces e Polimorfismo

Manutenção de programas

O programa principal

/*
 * Polimorfismo. Programa principal.
 */
import p1.aplic.correio.*;

public class Correio2 {
    public static void main(String[] args) {
        if(args.length != 1) {
            System.err.println("Sintaxe: java Correio2 nome");
            System.exit(1);
        }
        CorreioIU2 ciu = new CorreioIU2(args[0]);
        ciu.interfaceComUsuário();
    }
}

A classe CorreioIU2

C:\...\src>java -classpath .;packagep1\p1.jar Correio2 jacques
Nao ha mensagem.
exibir, texto, voz, excluir, +, -, quit? t
Para quem? ana
Assunto? vamos forrozar?
Conteudo da mensagem? (. para terminar)
Hoje aa noite, na Parque do Povo, ta bem?
tchau
o fofo
.
Nao ha mensagem.
exibir, texto, voz, excluir, +, -, quit? v
Para quem? ana
Assunto? uma musica pra voce ...
Arquivo de clip de audio? clip1.mid
Nao ha mensagem.
exibir, texto, voz, excluir, +, -, quit? q
Salvar CaixaPostal? s

C:\...\src>java -classpath .;packagep1\p1.jar Correio2 ana

  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 10:24 vamos forrozar?
    2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? exi
De: jacques
Data: 29/06/2001 10:24
Assunto: vamos forrozar?
Hoje aa noite, na Parque do Povo, ta bem?
tchau
o fofo

  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 10:24 vamos forrozar?
    2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? exc
  Num Remetente    Data             Assunto
>X  1 jacques      29/06/2001 10:24 vamos forrozar?
    2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? +
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 10:24 vamos forrozar?
>   2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? exi
Se tiver multimidia no computador, o clip deve estar tocando
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 10:24 vamos forrozar?
>   2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? exc
  Num Remetente    Data             Assunto
 X  1 jacques      29/06/2001 10:24 vamos forrozar?
>X  2 jacques      29/06/2001 10:24 uma musica pra voce ...
exibir, texto, voz, excluir, +, -, quit? q
Salvar CaixaPostal? s
/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */
package p1.aplic.correio;

import p1.io.*;
import p1.util.*;
import java.util.*;

/**
 * Classe que implementa uma interface simples (a caractere)
 * de manipulação de mensagens de correio eletrônico.
 * <p>
 * O programa manipula uma caixa postal de mensagens de correio eletrônico.
 * O funcionamento da interface é como segue. Um objeto dessa
 * classe deve ser criado com um argumento especificando o titular da caixa postal
 * a ser manipulada. Ao chamar o método principal (interfaceComUsuário()),
 * o conteúdo da caixa postal pode ser manipulado e novas mensagens podem ser enviadas.
 * Pode-se enviar correio textual ou de áudio.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class CorreioIU2 {
    private CaixaPostal caixa;
    
    /**
     * Construtor de uma interface com o usuário para manipular
     * uma caixa postal de correio eletrônico.
     * @param titular O titular da caixa postal que se deseja manipular.
     */
    public CorreioIU2(String titular) {
        caixa = new CaixaPostal(titular);
    }

    /**
     * Interface com o usuário para a manipulação de caixa postal.
     * A interface consiste basicamente de um laço de interpretação de comandos.
     * O conteúdo da caixa postal é mostrado na tela e um menu de comandos
     * é exibido. Os comandos disponíveis são:
     * <p><strong>exibir</strong>: exibe a mensagem corrente.
     * <p><strong>texto</strong>: envia uma nova mensagem textual de correio.
     * Neste caso, deve-se especificar ainda o destinatário, o assunto e
     * o conteúdo da mensagem propriamente dita. O remetente será o titular da caixa postal.
     * <p><strong>voz</strong>: envia uma nova mensagem de correio usando áudio.
     * Neste caso, deve-se especificar ainda o destinatário, o assunto e
     * o arquivo contendo o áudio da mensagem. Essa interface estranha foi usada porque
     * não queremos obrigar o uso de um microfone para gravar a mensagem.
     * O remetente será o titular da caixa postal.
     * <p><strong>excluir</strong>: marca a mensagem corrente para exclusão. Chamamos isso
     * de <strong>exclusão lógica</strong>. A exclusão em sí (física)
     * é feita ao salvar a caixa postal no final (vide o comando "quit").
     * <p><strong>+</strong>: avança para a próxima mensagem.
     * <p><strong>-</strong>: recua para a mensagem anterior.
     * <p><strong>quit</strong>: encerra a manipulação da caixa postal. Pede-se neste momento
     * se a caixa postal deve ser salva em disco ou não. Responda com 's' ou 'n'.
     * <p>Os comandos podem ser digitados de forma abreviada, desde que um número
     * suficiente de letras seja informado. Por exemplo, basta digitar "v" para
     * enviar uma mensagem nova de áudio.
     * Digitar "ex" não é suficiente, pois há dois comandos começando
     * com "ex". Deve-se digitar pelo menos "exc" (excluir) ou "exi" (exibir).
     */
    public void interfaceComUsuário() {
        while(true) {
            mostraResumoCaixaPostal(caixa);
            String cmd = Entrada.in.lerLinha("exibir, texto, voz, excluir, +, -, quit? ");
            if(cmd.startsWith("exi")) {
                Mensagem m = caixa.mensagemCorrente();
                if(m != null) {
                    m.exibir();
                }
            } else if(cmd.startsWith("t")) {
                String destinatário = obtemUmaLinha("Para quem? ");
                String assunto = obtemUmaLinha("Assunto? ");
                String conteúdo = obtemVáriasLinhas("Conteudo da mensagem? (. para terminar) ");
                enviarMensagemTexto(caixa.getTitular(), destinatário, assunto, conteúdo);
            } else if(cmd.startsWith("v")) {
                String destinatário = obtemUmaLinha("Para quem? ");
                String assunto = obtemUmaLinha("Assunto? ");
                String clip = obtemUmaLinha("Arquivo de clip de audio? ");
                enviarMensagemÁudio(caixa.getTitular(), destinatário, assunto, clip);
            } else if(cmd.startsWith("exc")) {
                caixa.excluir();
            } else if(cmd.startsWith("+")) {
                caixa.avançar();
            } else if(cmd.startsWith("-")) {
                caixa.recuar();
            } else if(cmd.startsWith("q")) {
                cmd = Entrada.in.lerLinha("Salvar CaixaPostal? ");
                if(cmd.startsWith("s")) {
                    caixa.salvar();
                }
                break;
            } else {
                System.out.println("Comando <" + cmd + "> desconhecido");
            }
        }
    }

    /**
     * Exibe na saída padrão um resumo da mensagens presentes na caixa postal.
     * @param caixa A caixa postal a ser exibida
     */
    // Observe que este método *não* é public
    private void mostraResumoCaixaPostal(CaixaPostal caixa) {
        Iterator it = caixa.iterator();
        if(!it.hasNext()) {
            System.out.println("Nao ha mensagem.");
            return;
        }
        // -16.16s significa um string (s) alinhado à esquerda (-)
        // com um mínimo de 16 caracteres e um máximo de 16 caracteres
        Formata f1 = new Formata("%-16.16s");
        Formata f2 = new Formata("%-40.40s");
        Formata f3 = new Formata("%3d");
        Formata f4 = new Formata("%-12.12s");
        System.out.println("  Num " + f4.form("Remetente") +
                           " " + f1.form("Data") +
                           " " + f2.form("Assunto"));
        int numMensagem = 1;
        while(it.hasNext()) {
            Mensagem m = (Mensagem)it.next();
            String cursor = " ";
            if(m == caixa.mensagemCorrente()) {
                cursor = ">";
            }
            String estado = m.isExcluída() ? "X" : " ";
            System.out.println(cursor + estado +
                                f3.form(numMensagem) + " " +
                                f4.form(m.getRemetente()) + " " +
                                f1.form(m.getDataEnvio().DDMMAAAAHHMM()) + " " +
                                f2.form(m.getAssunto()));
            numMensagem++;
        }
    }

    /** Método auxiliar para obter uma linha da entrada padrão, tendo
     * o cuidado de não aceitar uma linha vazia.
     * @param prompt O prompt a exibir ao usuário antes de ler a informação.
     * @return A linha lida.
     */
    // Observe que este método *não* é public
    private String obtemUmaLinha(String prompt) {
        String linha;
        while((linha = Entrada.in.lerLinha(prompt)).equals("")) {
            System.out.println("Favor fornecer alguma informacao");
        }
        return linha;
    }

    /** Método auxiliar para obter várias linhas da entrada padrão.
     * O final da entrada é indicado digitando "." sozinho no início
     * de uma linha.
     * @param prompt O prompt a exibir ao usuário antes de ler a informação.
     * @return As linhas lida, como string único. As linhas são separadas
     * por um caractere de separação de linha apropriado.
     */
    // Observe que este método *não* é public
    private String obtemVáriasLinhas(String prompt) {
        String resposta = "";
        String separador = System.getProperty("line.separator");
        String linha;
        System.out.println(prompt);
        while(!(linha = Entrada.in.lerLinha("")).equals(".")) {
            resposta += linha + separador;
        }
        return resposta;
    }

    /**
     * Envia uma mensagem textual de correio eletrônico para um destinatário.
     * @param remetente O remetente da mensagem.
     * @param destinatário O destinatário da mensagem.
     * @param assunto O assunto da mensagem.
     * @param conteúdo O conteúdo da mensagem, podendo conter várias linhas de texto.
     */
    // Observe que este método *não* é public
    private void enviarMensagemTexto(String remetente, String destinatário, String assunto, String conteúdo) {
        CaixaPostal caixaDestino = new CaixaPostal(destinatário);
        caixaDestino.inserir(new MensagemTexto(remetente, assunto, conteúdo));
        caixaDestino.salvar();
    }

    /**
     * Envia uma mensagem de áudio de correio eletrônico para um destinatário.
     * @param remetente O remetente da mensagem.
     * @param destinatário O destinatário da mensagem.
     * @param assunto O assunto da mensagem.
     * @param clip O arquivo de áudio contendo a mensagem.
     */
    // Observe que este método *não* é public
    private void enviarMensagemÁudio(String remetente, String destinatário, String assunto, String clip) {
        CaixaPostal caixaDestino = new CaixaPostal(destinatário);
        caixaDestino.inserir(new MensagemAudio(remetente, assunto, clip));
        caixaDestino.salvar();
    }
}

Polimorfismo

                Mensagem m = caixa.mensagemCorrente();
                if(m != null) {
                    m.exibir();
                }

wpe2.jpg (9081 bytes)

Mensagens de correio são "exibidas"

wpe2C.jpg (14343 bytes)

Animais "falam"

polifiguras.gif (5580 bytes)

Figuras geométricas são "desenhadas"

A interface Mensagem

/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */
package p1.aplic.correio;

import p1.aplic.geral.*;
import java.io.*;

/**
 * Interface para manipular uma mensagem de correio eletronico.
 * Uma mensagem contém um remetente, um assunto uma data de envio e algum conteúdo.
 * O conteúdo depende do tipo exato de mensagem (textual, áudio).
 * Uma mensagem pode ser exibida (lida) e marcada para exclusão.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public interface Mensagem  {
    /**
     * Recupera o remetente da mensagem
     * @return O remetente da mensagem
     */
    public String getRemetente();

    /**
     * Recupera o assunto da mensagem
     * @return O assunto da mensagem
     */
    public String getAssunto();

    /**
     * Recupera a data de envio da mensagem
     * @return A data de envio da mensagem
     */
    public Data getDataEnvio();

    /**
     * Informa se a mensagem foi lida ou não
     * @return true se a mensagem foi lida, false caso contrário
     */
    public boolean isLida();

    /**
     * Informa se a mensagem foi excluída ou não
     * @return true se a mensagem foi excluída, false caso contrário
     */
    public boolean isExcluída();

    /**
     * Marcar a mensagem como excluída.
     * A exclusão deve ser feita pela coleção que armazena as mensagens.
     * Um exemplo de tal coleção é CaixaPostal.
     */
    public void excluir();

    /**
     * Marcar a mensagem como não excluída.
     */
    public void marcarNãoExcluída();

    /**
     * Marcar a mensagem como não lida.
     */
    public void marcarNãoLida();

    /**
     * Testa a igualdade de um objeto com esta mensagem.
     * @param objeto O objeto a comparar com esta mensagem.
     * @return true se o objeto for igual a esta mensagem, false caso contrário.
     */
    public boolean equals(Object objeto);

    /**
     * Exibir a mensagem. Isso poderá imprimir algo na saída
     * ou provocar outras saídas relacionadas com a leitura da mensagem.
     * Após este método, a mensagem é considerada "lida".
     */
    public void exibir();

    /**
     * Forneça uma representação da mensagem como String
     * @return A representação da mensagem como String.
     */
    public String toString();
}

Implementação de uma interface: MensagemTexto

/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */

import p1.aplic.correio.*;
import p1.aplic.geral.*;
import java.io.*;

/**
 * Classe que representa uma mensagem normal de correio eletronico.
 *
 * Uma mensagem contém um remetente, um assunto uma data de envio e algum conteúdo.
 * O conteúdo depende do tipo exato de mensagem (textual, áudio).
 * Uma mensagem pode ser exibida (lida) e marcada para exclusão.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class MensagemTexto implements Mensagem {
    private static final int LIDA = 0x1;
    private static final int EXCLUÍDA = 0x2;
    private static final int NOVA = ~(LIDA | EXCLUÍDA);

    private String  remetente;
    private String  assunto;
    private String  conteúdo;
    private Data    dataEnvio;
    private int     estado;

    public MensagemTexto(String remetente, String assunto, String conteúdo) {
        this.remetente = remetente;
        this.assunto = assunto;
        this.conteúdo = conteúdo;
        dataEnvio = new Data();
        estado = NOVA;
    }

    /**
     * Recupera o remetente da mensagem
     * @return O remetente da mensagem
     */
    public String getRemetente() {
        return remetente;
    }

    /**
     * Recupera o assunto da mensagem
     * @return O assunto da mensagem
     */
    public String getAssunto() {
        return assunto;
    }

    /**
     * Recupera o conteúdo da mensagem
     * @return O conteúdo da mensagem
     */
    public String getConteúdo() {
        return conteúdo;
    }

    /**
     * Recupera a data de envio da mensagem
     * @return A data de envio da mensagem
     */
    public Data getDataEnvio() {
        return dataEnvio;
    }

    /**
     * Informa se a mensagem foi lida ou não
     * @return true se a mensagem foi lida, false caso contrário
     */
    public boolean isLida() {
        return (estado & LIDA) == LIDA;
    }

    /**
     * Informa se a mensagem foi excluída ou não
     * @return true se a mensagem foi excluída, false caso contrário
     */
    public boolean isExcluída() {
        return (estado & EXCLUÍDA) == EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como excluída.
     * A exclusão deve ser feita pela coleção que armazena as mensagens.
     * Um exemplo de tal coleção é CaixaPostal.
     */
    public void excluir() {
        estado |= EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não excluída.
     */
    public void marcarNãoExcluída() {
        estado &= ~EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não lida.
     */
    public void marcarNãoLida() {
        estado &= ~LIDA;
    }

    /**
     * Testa a igualdade de um objeto com esta mensagem.
     * @param objeto O objeto a comparar com esta mensagem.
     * @return true se o objeto for igual a esta mensagem, false caso contrário.
     */
    public boolean equals(Object objeto) {
        if(! (objeto instanceof Mensagem)) {
            return false;
        }
        Mensagem outra = (Mensagem)objeto;
        return getRemetente().equals(outra.getRemetente())
                && getAssunto().equals(outra.getAssunto())
                && getConteúdo().equals(outra.getConteúdo());
    }

    /**
     * Exibir a mensagem. Os dados da mensagem são apresentados na saída padrão.
     * Após este método, a mensagem é considerada "lida".
     */
    public void exibir() {
        System.out.println("De: " + remetente);
        System.out.println("Data: " + dataEnvio.DDMMAAAAHHMM());
        System.out.println("Assunto: " + assunto);
        System.out.println(conteúdo);
        estado |= LIDA;
    }

    /**
     * Forneça uma representação da mensagem como String
     * @return A representação da mensagem como String.
     */
    public String toString() {
        return "Remetente: " + remetente +
               ", Data: " + dataEnvio.DDMMAAAAHHMM() +
               ", Assunto: " + assunto +
               ", Conteúdo: " + conteúdo;
    }
}

Implementação de uma interface: MensagemAudio

/*
 * Desenvolvido para a disciplina Programacao 1
 * Curso de Bacharelado em Ciência da Computação
 * Departamento de Sistemas e Computação
 * Universidade Federal da Paraíba
 *
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */

import p1.aplic.correio.*;
import p1.aplic.geral.*;
import java.io.*;
import java.net.*;
import java.applet.*;

/**
 * Classe que representa uma mensagem de áudio de correio eletronico.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 1999 Universidade Federal da Paraíba.
 */

public class MensagemAudio implements Mensagem {
    private static final int LIDA = 0x1;
    private static final int EXCLUÍDA = 0x2;
    private static final int NOVA = ~(LIDA | EXCLUÍDA);

    private String  remetente;
    private String  assunto;
    private String  arquivoÁudio;
    private Data    dataEnvio;
    private int     estado;

    /**
     * Cria uma mensagem de áudio de correio eletrônico
     * @param remetente O remetente da mensagem
     * @param assunto O assunto da mensagem
     * @param arquivoÁudio O arquivo contendo o áudio da mensagem
     */
    public MensagemAudio(String remetente, String assunto, String arquivoÁudio) {
        this.remetente = remetente;
        this.assunto = assunto;
        this.arquivoÁudio = arquivoÁudio;
        dataEnvio = new Data();
        estado = NOVA;
    }

    /**
     * Recupera o remetente da mensagem
     * @return O remetente da mensagem
     */
    public String getRemetente() {
        return remetente;
    }

    /**
     * Recupera o assunto da mensagem
     * @return O assunto da mensagem
     */
    public String getAssunto() {
        return assunto;
    }

    /**
     * Recupera o arquivo de áudio da mensagem.
     * @return O arquivo de áudio da mensagem.
     */
    public String getarquivoÁudio() {
        return arquivoÁudio;
    }

    /**
     * Recupera a data de envio da mensagem
     * @return A data de envio da mensagem
     */
    public Data getDataEnvio() {
        return dataEnvio;
    }

    /**
     * Informa se a mensagem foi lida ou não
     * @return true se a mensagem foi lida, false caso contrário
     */
    public boolean isLida() {
        return (estado & LIDA) == LIDA;
    }

    /**
     * Informa se a mensagem foi excluída ou não
     * @return true se a mensagem foi excluída, false caso contrário
     */
    public boolean isExcluída() {
        return (estado & EXCLUÍDA) == EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como excluída.
     * A exclusão deve ser feita pela coleção que armazena as mensagens.
     * Um exemplo de tal coleção é CaixaPostal.
     */
    public void excluir() {
        estado |= EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não excluída.
     */
    public void marcarNãoExcluída() {
        estado &= ~EXCLUÍDA;
    }

    /**
     * Marcar a mensagem como não lida.
     */
    public void marcarNãoLida() {
        estado &= ~LIDA;
    }

    /**
     * Exibir a mensagem. O arquivo de áudio é tocado.
     * Após este método, a mensagem é considerada "lida".
     */
    public void exibir() {
        try {
            URL u = new URL("file", "localhost", arquivoÁudio);
            AudioClip clip = Applet.newAudioClip(u);
            System.out.println("Se tiver multimidia no computador, o clip deve estar tocando");
            clip.play();
        } catch(Exception e) {
            System.out.println("Nao pode abrir Audio Clip: " + arquivoÁudio);
        }
        estado |= LIDA;
    }   

    /**
     * Testa a igualdade de um objeto com esta mensagem.
     * @param objeto O objeto a comparar com esta mensagem.
     * @return true se o objeto for igual a esta mensagem, false caso contrário.
     */
    public boolean equals(Object objeto) {
        if(! (objeto instanceof MensagemAudio)) {
            return false;
        }
        MensagemAudio outra = (MensagemAudio)objeto;
        return super.equals(objeto) &&
               getarquivoÁudio().equals(outra.getarquivoÁudio());
    }

    /**
     * Forneça uma representação da mensagem como String
     * @return A representação da mensagem como String.
     */
    public String toString() {
        return "Remetente: " + remetente +
               ", Data: " + dataEnvio.DDMMAAAAHHMM() +
               ", Assunto: " + assunto +
               ", Arquivo de áudio: " + arquivoÁudio;
    }
}

Uso de interfaces: chamadas polimórficas

                Mensagem m = caixa.mensagemCorrente();
                if(m != null) {
                    m.exibir();
                }
public class CaixaPostal implements Serializable {
    private List mensagens;
    ...

    /**
     * Insira uma nova mensagem no final da caixa postal
     * @param m A Mensagem sendo inserida.
     */
    public void inserir(Mensagem m) {
        mensagens.add(m);
        índiceMensagemCorrente = Math.max(índiceMensagemCorrente, 0);
    }

    /**
     * Recupera a mensagem corrente.
     * <p>A caixa inclui um "cursor" de mensagem. Isto é, existe
     * o conceito de "mensagem corrente" e pode-se avançar e recuar
     * na lista de mensagens (mudando assim a mensagem corrente).
     * @return A mensagem corrente.
     */
    public Mensagem mensagemCorrente() {
        return índiceMensagemCorrente >= 0 ? (Mensagem)mensagens.get(índiceMensagemCorrente) : null;
    }

    /**
     * Excluir a mensagem Corrente da caixa postal.
     * A exclusão é apenas lógica. A mensagem está marcada para ser excluída
     * mas só é, de fato, excluída ao salvar a caixa postal.
     * @return true, se houve mensagem excluída, false caso contrário (caixa vazia)
     */
    public boolean excluir() {
        if(índiceMensagemCorrente >= 0 && índiceMensagemCorrente < mensagens.size()) {
            mensagemCorrente().excluir();
            índiceMensagemCorrente = Math.min(índiceMensagemCorrente, mensagens.size()-1);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Salvar a caixa postal em disco.
     * Neste momento, as mensagens marcadas para exclusão são removidas
     * (isto é, não são gravadas em disco)
     */
    public void salvar() {
        // primeiro, remover as mensagens excluídas
        Iterator it = iterator();
        while(it.hasNext()) {
            Mensagem m = (Mensagem)it.next();
            if(m.isExcluída()) {
                it.remove();
            }
        }
        ...
    }
    ...
}

Mais manutenção de código

C:\..\src>java -classpath .;packagep1\p1.jar Correio3 jacques
Nao ha mensagem.
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? t
Para quem? ana
Assunto? msg1
Conteudo da mensagem? (. para terminar)
msg1
.
Nao ha mensagem.
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? m
Para quem? ana
Assunto? msg2
Conteudo da mensagem? (. para terminar)
msg2
.
Nao ha mensagem.
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? t
Para quem? ana
Assunto? msg3
Conteudo da mensagem? (. para terminar)
msg3
.
Nao ha mensagem.
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? q
Salvar CaixaPostal? s

C:\...\src>java -classpath .;packagep1\p1.jar Correio3 ana

  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 13:06 msg1
    2 jacques      29/06/2001 13:06 msg2
    3 jacques      29/06/2001 13:06 msg3
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? exi
De: jacques
Data: 29/06/2001 13:06
Assunto: msg1
msg1

  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 13:06 msg1
    2 jacques      29/06/2001 13:06 msg2
    3 jacques      29/06/2001 13:06 msg3
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? +
  Num Remetente    Data             Assunto
    1 jacques      29/06/2001 13:06 msg1
>   2 jacques      29/06/2001 13:06 msg2
    3 jacques      29/06/2001 13:06 msg3
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? exi
De: jacques
Data: 29/06/2001 13:06
Assunto: msg2
msg2

  Num Remetente    Data             Assunto
    1 jacques      29/06/2001 13:06 msg1
>X  2 jacques      29/06/2001 13:06 msg2
    3 jacques      29/06/2001 13:06 msg3
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? q
Salvar CaixaPostal? s


C:\...\src>java -classpath .;packagep1\p1.jar Correio3 ana

  Num Remetente    Data             Assunto
>   1 jacques      29/06/2001 13:06 msg1
    2 jacques      29/06/2001 13:06 msg3
exibir, texto, missaoimpossivel, voz, excluir, +, -, quit? q
Salvar CaixaPostal? s
    /**
     * Exibir a mensagem. Os dados da mensagem são apresentados na saída padrão.
     * Após este método, a mensagem se auto-destroi.
     */
    public void exibir() {
        System.out.println("De: " + remetente);
        System.out.println("Data: " + dataEnvio.DDMMAAAAHHMM());
        System.out.println("Assunto: " + assunto);
        System.out.println(conteúdo);
        estado |= LIDA;
        excluir();
    }

Mais discussão de polimorfismo

Implementação do polimorfismo: Ligação dinâmica

Exemplos de interfaces da API Java

UML

Correio3.gif (24631 bytes)

Correio3-bola.gif (20492 bytes)

oo-4 programa anterior próxima