Orientação a Objeto - Reuso com Herança

Objetivos da seção

Reuso com herança

Fatorando o que há de comum

/*
 * 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.*;

/**
 * Classe abstrata que representa 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 class MensagemAbstrata implements Mensagem {
  protected static final int LIDA = 0x1;
  protected static final int EXCLUÍDA = 0x2;
  protected static final int NOVA = ~(LIDA | EXCLUÍDA);

  protected String  remetente;
  protected String  assunto;
  protected Data    dataEnvio;
  protected int     estado;

  /**
   * 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 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;
  }
}

Adicionando métodos ao núcleo comum

  protected MensagemAbstrata(String remetente, String assunto) {
    this.remetente = remetente;
    this.assunto = assunto;
    dataEnvio = new Data();
    estado = NOVA;
  }
  /**
   * 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());
  }

 

Adicionando métodos abstratos

/*
 * 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.*;

/**
 * Classe abstrata que representa 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 abstract class MensagemAbstrata implements Mensagem {
  protected static final int LIDA = 0x1;
  protected static final int EXCLUÍDA = 0x2;
  protected static final int NOVA = ~(LIDA | EXCLUÍDA);

  protected String  remetente;
  protected String  assunto;
  protected Data    dataEnvio;
  protected int     estado;

  // ...

  /**
   * 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 abstract void exibir();

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

 

Completando o trabalho com herança

/*
 * 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.*;

/**
 * Classe que representa uma mensagem normal 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 MensagemTexto extends MensagemAbstrata {
  protected String  conteúdo;

  /**
   * Cria uma mensagem textual de correio eletrônico
   * @param remetente O remetente da mensagem
   * @param assunto O assunto da mensagem
   * @param contéudo O conteúdo da mensagem, podendo conter várias linhas
   */
  public MensagemTexto(String remetente, String assunto, String conteúdo) {
    super(remetente, assunto);
    this.conteúdo = conteúdo;
  }

  /**
   * Recupera o conteúdo da mensagem.
   * O conteúdo é um String podendo conter várias linhas.
   * @return O conteúdo da mensagem
   */
  public String getConteúdo() {
    return conteú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;
  }

  /**
   * 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 MensagemTexto)) {
      return false;
    }
    MensagemTexto outra = (MensagemTexto)objeto;
    return super.equals(objeto) &&
           getConteúdo().equals(outra.getConteúdo());
  }

  /**
   * 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;
  }
}

Representando herança em UML

MensagemTexto.gif (14718 bytes)

A classe 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.
 */
package 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 extends MensagemAbstrata {
  protected String  arquivoÁudio;

  /**
   * 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) {
    super(remetente, assunto);
    this.arquivoÁudio = arquivoÁudio;
  }

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

  /**
   * 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;
  }
}

A classe MensagemMissaoImpossivel

/*
 * 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) 2001 Universidade Federal da Paraíba.
 * Não redistribuir sem permissão.
 */
package p1.aplic.correio;

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

/**
 * Classe que representa uma mensagem textual de correio eletronico mas que se auto-destroi depois de lida.
 *
 * @author   Jacques Philippe Sauvé, jacques@dsc.ufpb.br
 * @version 1.0
 * <br>
 * Copyright (C) 2001 Universidade Federal da Paraíba.
 */

public class MensagemMissaoImpossivel extends MensagemTexto {
  /**
   * Cria uma mensagem textual de correio eletrônico
   * @param remetente O remetente da mensagem
   * @param assunto O assunto da mensagem
   * @param contéudo O conteúdo da mensagem, podendo conter várias linhas
   */
  public MensagemMissaoImpossivel(String remetente, String assunto, String conteúdo) {
    super(remetente, assunto, conteúdo);
  }

  /**
   * 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() {
    super.exibir();
    excluir();
  }

  /**
   * 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 MensagemMissaoImpossivel)) {
      return false;
    }
    MensagemMissaoImpossivel outra = (MensagemMissaoImpossivel)objeto;
    return super.equals(objeto);
  }
}

HierarquiaMensagens.gif (17627 bytes)

Consequências da herança

Poder de substituição de um objeto por outro

        MensagemTexto m = new MensagemTexto(remetente, assunto, conteúdo);
        m.exibir();
        m.excluir();

Polimorfismo

                Mensagem m = ...;
                m.exibir();
                MensagemAbstrata m = ...;
                m.exibir();
public interface MensagemMultimidia extends Mensagem {
   public boolean isÁudio();
   public boolean isVídeo();
   public boolean isAnimação();
}

Mais sobre hierarquias de classes

public class CaixaPostal {

public class CaixaPostal extends Object {

hierarquia.gif (6507 bytes)

Upcasting e downcasting

// ...
public class CaixaPostal {
  private List  mensagens;
  private int     índiceMensagemCorrente;

  // ...

  public void inserir(Mensagem m) {
    mensagens.add(m);
    índiceMensagemCorrente = Math.max(índiceMensagemCorrente, 0);
  }

  public Mensagem mensagemCorrente() {
    return índiceMensagemCorrente >= 0 ? (Mensagem)mensagens.get(índiceMensagemCorrente) : null;
  }

  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();
      }
    }
    // ... salva em disco
  }
}
    Object x = new MensagemTexto(remetente, assunto, conteúdo);
    System.out.println((String)x);

Exemplos do uso de herança

No mundo das cartas

Carta.gif (15005 bytes)

HierarquiaBaralho.gif (10681 bytes)

HierarquiaMao.gif (9219 bytes)

No mundo bancário

HierarquiaConta.gif (17164 bytes)

No mundo Java

Collection.gif (9933 bytes)

public interface List extends Collection { ... }
public interface Set extends Collection { ... }
public interface SortedSet extends Collection, Set { ... }

Exercício

oo-5 programa anterior próxima