Interfaces
Herança de classe versus herança de interface
- Há uma diferença grande entre uma classe e seu tipo
- A classe define uma implementação
- O tipo define apenas a interface oferecida para acessar objetos da classe
- Um objeto pode ter muitos tipos
- Classes diferentes podem ter o mesmo tipo
- Herança de classe significa herança de implementação
- A sub-classe herda a implementação da super-classe
- É um mecanismo para compartilhar código e representação
- Herança de interface (ou sub-tipos) descreve quando um objeto pode ser usado em vez de
outro
- Ao fazer herança de classe, automaticamente faz também herança de interface
- Algumas linguagens não permitem definir tipos separadamente de classes
- Mas, neste caso, a classe puramente abstrata serve
"Program to an interface, not an implementation"
- O fato de que a herança de implementação permite facilmente reusar a funcionalidade
de uma classe é interessante mas não é o aspecto mais importante a ser considerado
- Herança oferece a habilidade de definir famílias de objetos com interfaces idênticas
- Isso é extremamente importante pois permite desacoplar um objeto de seus clientes
através do polimorfismo
- A herança de interface corretamente usada (sem eliminar partes da interface nas
sub-classes) acaba criando sub-tipos, permitindo o polimorfismo
- Programar em função de uma interface e não em função de uma implementação (uma
classe particular) permite o polimorfismo e fornece as seguintes vantagens:
- Clientes permanecem sem conhecimento do tipo de objetos que eles usam, desde que os
objetos obedeçam a interface
- Clientes permanecem sem conhecimento das classes que implementam tais objetos
- A interface é o que há de comum
- A flexibilidade vem da possibilidade de mudar a implementação da interface, até em
tempo de execução, já que o polimorfismo é implementado com "late binding"
feito em tempo de execução
- Em java, uma classe pode implementar várias interfaces
- Isso permite ter mais polimorfismo mesmo sem que as classes pertençam a uma mesma
hierarquia
Exemplo no uso de interfaces
- Temos vários tipos de composites (coleções) que não pertencem a uma mesma hierarquia
- ColeçãoDeAlunos
- ColeçãoDeProfessores
- ColeçãoDeDisciplinas
- Temos um cliente comum dessas coleções
- Digamos um selecionador de objetos usado numa interface gráfica para abrir uma list box
para selecionar objetos com um determinado nome
- Exemplo:
- Quero listar todos os alunos com nome "João" e exibí-los numa list box para
escolha pelo usuário
- Idem para listar professores com nome "Alfredo"
- Idem para listar disciplinas com nome "Programação"
- Queremos fazer um único cliente para qualquer uma das coleções
- O exemplo abaixo tem polimorfismo em dois lugares
interface SelecionávelPorNome {
Iterator getIteradorPorNome(String nome);
}
interface Nomeável {
String getNome();
}
classe ColeçãoDeAlunos implements SelecionávelPorNome {
// ...
Iterator getIteradorPorNome(String nome) {
// ...
}
}
classe Aluno implements Nomeável {
// ...
String getNome() { ... }
}
classe ColeçãoDeProfessores implements SelecionávelPorNome {
// ...
Iterator getIteradorPorNome(String nome) {
// ...
}
}
classe Professor implements Nomeável {
// ...
String getNome() { ... }
}
classe ColeçãoDeDisciplinas implements SelecionávelPorNome {
// ...
Iterator getIteradorPorNome(String nome) {
// ...
}
}
classe Disciplina implements Nomeável {
// ...
String getNome() { ... }
}
classe ComponenteDeSeleção {
Iterator it;
// observe o tipo do parâmetro (uma interface)
public ComponenteDeSeleção(SelecionávelPorNome coleção, String nome) {
it = coleção.getIteradorPorNome(nome); // chamada polimórfica
}
// ...
void geraListBox() {
response.out.println("<select name=\"nome\" size=\"1\">");
while(it.hasNext()) {
int i = 1;
// observe o tipo do objeto
Nomeável obj = (Nomeável)it.next();
response.out.println("<option value=\"escolha" + i + "\">" +
obj.getNome() + // chamada polimórfica
"</option>");
}
response.out.println("</select>");
}
}
// Como usar o código acima num servlet:
// supõe que as coleções usam o padrão Singleton
ComponenteDeSeleção cds =
new ComponenteDeSeleção(ColeçãoDeAlunos.getInstance(), "João");
cds.geraListBox();
cds = new ComponenteDeSeleção(ColeçãoDeDisciplinas.getInstance(), "Programação");
cds.geraListBox();
Como achar interfaces
- Procure assinaturas repetidas
- Exemplo: várias classes que representam coisas que podem ser vendidas indicam o uso de
uma interface VendávelIF
- Onde há delegação, um objeto se esconde atrás de outro: deve haver uma interface
comum
- Procure métodos que poderiam ser usadas em aplicações semelhantes e use interfaces
para que a reusabilidade das classes clientes seja maior
- Exemplo: muitas coisas poderiam ser reserváveis, não só passagens de avião
- Exemplo: muitas coisas pode ser alugadas, não só fitas de vídeo
- Exemplo: muitos objetos são clonáveis
- Procure mudanças futuras (novos objetos que poderiam aparecer) e coloque as
semelhanças sob controle de interfaces
- Há, entretanto, pessoas que não concordam em "pensar muito na frente"
- Vide "Extreme Programming" adiante ...
proj2-2 programa próxima