Polimorfismo, Interfaces, Classes Abstractas

From Wiki**3

Programação com Objectos
Introduction
Creation and Destruction
Inheritance & Composition
Abstraction & Polymorphism
Code Organization
Java Topics
Inner Classes
Enumerations
Data Structures
Exceptions
Input/Output
RTTI
Other Topics
JUnit Tests
UML Topics
Design Patterns
"Simple" Factory
Composite & Visitor
Command
Strategy & State
Template Method
Observer
Abstract Factory
Decorator & Adapter
Façade (aka Facade)

Interfaces

  • Princípios e propriedades
  • Separação de interface e implementação

Noção de classe abstracta

  • Propriedades
  • Contraste com interfaces

Abstracção, Polimorfismo

O conceito de abstracção está relacionado com a capacidade de descrição de conceitos "abstractos", i.e., conceitos que descrevem múltiplos conceitos concretos. Em linguages OO, como Java ou C++, estes conceitos abstractos correspondem a classes abstractas (Java e C++), interfaces (Java; ou classes virtuais puras em C++), ou mesmo classes concretas não específicas (Animal, por exemplo, por oposição a Cão ou Gato). Nestas linguagens, existe ainda a possibilidade de abstracção genérica, i.e., definição de classes com dependência de tipos não especificados quando a classe é escrita. Estão neste caso, os generics do Java (e.g. ArrayList<Integer>) e os templates do C++ (e.g. std::vector<int>).

O conceito de polimorfismo corresponde à capacidade de referir objectos através de tipos que não o seu próprio ou de tipos genéricos. Quando se usam tipos genéricos, o polimorfismo consiste na manipulação dos objectos numa estrutura genérica (exemplos acima). Na presença de herança, i.e., quando existem hierarquias de classes, tem-se outro tipo de polimorfismo: o polimorfismo de inclusão. Este tipo de polimorfismo permite referir com tipos superiores na hierarquia objectos de tipos inferiores. O processo corresponde à definição de uma referência/ponteiro de um tipo superior que é utilizado para manipular um objecto de um tipo inferior.

Animal a = new Gato();  // upcasting (always safe) [Java]

As linguagens OO permitem este tipo de operação, pois um tipo mais abstracto é uma descrição resumida para um tipo mais concreto. Existe uma conversão implícita do tipo da referência concreta para o tipo da abstracta, designado por upcast. Esta conversão é sempre segura, no sentido de o tipo superior é sempre uma descrição admissível para o tipo inferior (relação is-a). No entanto, em C++, é possível controlar a sua utilização (herança privada, por exemplo). A conversão no sentido contrário (downcast) não é segura, pois um tipo superior pode referir vários inferiores que podem não estar relacionados entre si.

Além dos tipos de polimorfismo apresentados acima, e que são importantes para o desenho e implementação de aplicações OO, as linguagens modernas possuem ainda o polimorfismo associado aos tipos primitivos e que é, em geral, traduzido por conversões implícitas de tipo e representação em memória (int -> float, por exemplo).

As consequências para a programação são positivas: a abstracção e o polimorfismo permitem código para tipos menos específicos (ou mesmo genéricos) que é utilizável com tipos mais específicos (numa hierarquia de classes), ou concretos e definidos independentemente da classe (como é o caso dos genéricos -- note-se que podem existir algumas restrições pontuais). Em termos de gestão da produção de código, estes aspectos são importantes para a reutilização e desenvolvimento incremental.

Definição de métodos: overloading vs. overriding

  • Overloading: definição de métodos com o mesmo nome, mas com diferenças nos argumentos (tipo, número ou ambos) na mesma ou em classes relacionadas;
  • Overriding: redefinição de um método definido anteriormente por uma das superclasses da hierarquia de uma classe.
  • Overloading: Gato(int age) {...} e Gato(String name) {...}
  • Overriding: redefinição por parte de Gato.respirar() de Animal.respirar() (sendo Gato uma subclasse de Animal)

Selecção do método a invocar

  • early binding -- o método a invocar é conhecido em tempo de compilação (e.g., final em Java e não-virtual em C++)
  • late binding -- o método a invocar é apenas conhecido em tempo de execução (habitual em Java; única possibilidade em PHP e outras linguagens semelhantes; e métodos declarados com virtual em C++)

Outros aspectos

  • Discussão de aspectos problemáticos

Exemplos

Exercícios