Polimorfismo, Interfaces, Classes Abstractas

From Wiki**3

The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
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