Polimorfismo, Interfaces, Classes Abstractas/Exemplos Simples de Interfaces

From Wiki**3

< Polimorfismo, Interfaces, Classes Abstractas

Encontram-se nas secções seguintes exemplos do conceito de interface. A primeira secção ilustra a maior ou menor capacidade de definição do conceito em duas linguagens:

  • Java, onde o conceito é nativo
  • C++, onde o conceito é aproximado por outro

A segunda secção (Chihuahua) mostra um exemplo de uma aplicação completa, onde são utilizadas interfaces.

Interfaces em Java e C++

Java

A definição de uma interface, sintacticamente, corresponde a um elenco de métodos, indicando-se, além do nome do método, apenas os tipos dos argumentos e do retorno. É admissível a definição de constantes: identificadores como os dos atributos de qualquer classe. No entanto, estes "atributos" são implicitamente static e final.

Considere-se a interface Aluno que especifica os métodos a fornecer por qualquer aluno.

 interface Aluno {
   void estudar();
 }

De modo análogo, considere-se a definição da interface Docente:

 interface Docente {
   void leccionar();
 }

Utilizando as duas interfaces anteriores e definindo alguns métodos adicionais, é possível modelar a interface de um aluno de doutoramento que, por hipótese, dá aulas (por exemplo, como forma de pagar as propinas).

 interface Doutorando extends Aluno, Docente {
   void escreverTese();
   void defenderTese();
 }

C++

início de secção opcional

Como em C++ não há o conceito de interface, para definir os conceitos acima é necessário recorrer ao conceito mais próximo: classes virtuais puras (i.e., classes abstractas). O exemplo Java acima, agora aproximado em C++, seria então escrito da seguinte forma.

Classe ("interface") aluno:

 class Aluno {
 public:
   void estudar() = 0;
 };

Classe ("interface") docente:

 class Docente {
 public:
   void leccionar() = 0;
 };

Classe ("interface") doutorando:

 class Doutorando : public Aluno, Docente {
 public:
   void escreverTese() = 0;
   void defenderTese() = 0;
 };

Note-se que, apesar de se poder aproximar o conceito de interface através de classes abstractas, os dois conceitos diferem substancialmente. Note-se ainda que o paralelo para as classes abstactas de C++ em Java são igualmente classes abstractas (definidas utilizando a palavra chave abstract) e não as interfaces.

fim de secção opcional

Chihuahua

O seguinte exemplo ilustra a utilização de interfaces em Java. Note-se que, além das interfaces, são também utilizadas classes abstractas, por forma a contrastar a utilização de cada conceito. O diagrama UML fornece uma panorâmica do conjunto de interfaces e classes: a amarelo estão representadas as interfaces e a verde as classes abstractas; as classes normais estão a branco.

Diagrama de classes para o exemplo descrito.

O exemplo implementa vários conceitos, sendo os principais o de cão e o de vigilante. São definidos outros conceitos que especializam estes e outros que fornecem implementações concretas de cada um. Assim, o conceito de robot é o de um vigilante automático e o de cão de guarda um vigilante canino.

São utilizadas as seguintes interfaces e classes: Cão, Vigilante, CãoDeGuarda, CãoPastor, Chihuahua, Robot, XP, XP2003.

Cão

A interface Cão define as assinaturas dos métodos a que qualquer classe que implemente um cão deve saber responder.

 interface Cão {
   void ladrar();
   int  nPatas();
 }

Embora nada seja expresso na interface, além da assinatura, assume-se que a semântica a associar a cada método é a seguinte:

  • ladrar - executa a acção de produzir um latido
  • nPatas - calcula/retorna o número de patas do cão

As classes que implementem a interface, embora não sejam obrigadas a implementar esta semântica, têm todo o interesse em fazê-lo.

Vigilante

Por seu turno, a interface Vigilante define as assinaturas dos métodos a que uma entidade "vigilante" deve saber responder.

 interface Vigilante {
   boolean háIntrusos();
   void    soarAlarme();
 }

A semântica a associar pelas implementações é a seguinte:

  • háIntrusos - retorna true se tiverem sido detectados intrusos
  • soarAlarme - executa a acção de activar um alarme, e.g. um sinal sonoro

Robot

A interface Robot é uma especialização de Vigilante: é um vigilante robotizado que sabe avisar e destruir intrusos.

 interface Robot extends Vigilante {
   void avisarIntrusos();
   void destruirIntrusos();
 }

As implementações da interface Robot, além do que já se disse para a interface Vigilante, devem fornecer a seguinte semântica por método:

  • avisarIntrusos - deve ser emitido um aviso (possivelmente, porque depois se segue a invocação do método destruirIntrusos - mas não há qualquer garantia...)
  • destruirIntrusos - a acção a executar corresponde à destruição dos intrusos

Cão de Guarda

A interface CãoDeGuarda, de modo análogo a Robot define a assinatura das implementações de um cão de guarda, i.e., um cão vigilante.

 interface CãoDeGuarda extends Cão, Vigilante {
   void morder();
 }

Note-se a utilização de herança múltipla.

Cão Pastor

A primeira classe deste exemplo é CãoPastor. Esta classe implementa parte da interface de um cão de guarda e deixa para as suas subclasses a especificidade associada ao método ladrar. Embora abstracta, esta classe é uma implementação (ainda que parcial) da interface.

 public abstract class CãoPastor implements CãoDeGuarda {
   public final static int N_PATAS = 4;
 
   // métodos privados
   private void    fecharBoca()   { /* qualquer coisa */ }
   private boolean háPredadores() {
     /* qualquer coisa */
     return true;
   }
 
   // interface CãoDeGuarda
   public void morder() { fecharBoca(); }
 
   // inteface Cão
   public int  nPatas() { return N_PATAS; }
   public abstract void ladrar();
 
   // interface Vigilante
   public void    soarAlarme() { ladrar(); }
   public boolean háIntrusos() { return háPredadores(); }
 }

Chihuahua

Um exemplo de uma classe (não abstracta, i.e., implementa ladrar) derivada de CãoDeGuarda é a que se segue. Esta classe apenas necessita de implementar o método ladrar para ficar completa.

 public class Chihuahua extends CãoPastor {
   public void ladrar() { System.out.println("guau, guau"); }
 }

XP

Supõe-se que a classe XP existe independentemente das outras descritas até aqui (foi, por exemplo, definida para outro fim). Supõe-se, contudo, que contém funcionalidade útil para uma possível implementação de um robot, i.e., para uma classe que implemente a interface Robot.

 public class XP {
   public void    reboot()     { System.out.println("See ya!"); }
   public void    shutdown()   { System.out.println("Bye!"); }
   public void    crash()      { System.out.println("Nooo! Argh!!!"); }
   public boolean háIntrusos() { return false; } // detector de vírus
 }

Note-se a coincidência do nome háIntrusos: existe na classe XP e na interface Vigilante (da qual Robot herda parte da sua especificação). É necessário garantir que a semântica pretendida é a que o método realmente fornece.

XP2003

Esta é uma implementação de Robot que reutiliza XP.

 public class XP2003 extends XP implements Robot {
   // interface Robot
   public void avisarIntrusos()   { System.out.println("Isto é o último aviso!"); }
   public void destruirIntrusos() { System.out.println("Eu avisei..."); }
 
   // interface Vigilante
   public void soarAlarme() { System.out.println("金曜日です!"); }
 
   //public boolean háIntrusos() { return true; } // herdado de XP...
 }

Note-se que o método háIntrusos é implementado pela superclasse (XP). A consideração deste aspecto é de importância crucial, pois pode introduzir erros se o comportamento não for o desejado (o que provavelmente acontece: em XP, os intrusos são vírus -- por hipótese -- e em XP2003, uma implementação de um vigilante robotizado, a semântica é outra).

Aplicação

Considere-se a seguinte classe que exercita os conceitos anteriores:

 public class Teste {
   public static void main(String[] args) {
     Cão       c = new Chihuahua();
     Vigilante v = new Chihuahua();
     CãoPastor p = new Chihuahua();
     Robot     r = new XP2003();
     XP        x = new XP();
     XP        y = new XP2003();
 
     c.ladrar();
     v.soarAlarme();
     ((Chihuahua)v).ladrar();
     p.soarAlarme();
     r.avisarIntrusos();
     r.soarAlarme();
     x.reboot();
     y.crash();
     ((XP2003)y).soarAlarme();
   }
 }

Resultado

O resultado da aplicação acima é o seguinte:

 $ java Teste
 guau, guau
 guau, guau
 guau, guau
 guau, guau
 Isto é o último aviso!
 金曜日です!
 See ya!
 Nooo! Argh!!!
 金曜日です!