Upload
anakin
View
47
Download
0
Embed Size (px)
DESCRIPTION
PROGRAMAÇÃO ORIENTADA A PROCEDIMENTOS. Paradigma de software mais popular na década de 70 Concentra-se em subprogramas e bibliotecas de subprogramas Computações: os dados são enviados aos subprogramas Exemplo: um array é passado como parâmetro a um subprograma de classificação. - PowerPoint PPT Presentation
Citation preview
PROGRAMAÇÃO ORIENTADA A
PROCEDIMENTOS
Paradigma de software mais popular na década de 70
Concentra-se em subprogramas e bibliotecas de subprogramas
Computações: os dados são enviados aos subprogramas
Exemplo: um array é passado como parâmetro a um subprograma de classificação
PROGRAMAÇÃO ORIENTADA A DADOS
(OBJETOS)
"Linguagens baseadas em dados" Raízes: Simula67 Smalltalk80 - considerada a única
linguagem puramente OO Tipos de dados abstratos Herança Polimorfismo
PROGRAMAÇÃO ORIENTADA A DADOS
(OBJETOS) II
Computações realizam-se do seguinte modo: sobre um objeto-dados é invocado um método associado a este objeto-dados
Exemplo: o processo de classificação de um array é ativado invocando-se este método no objeto específico
HERANÇA
É o centro da programação orientada a objetos
Na década de 80 tornou-se patente aos desenvolvedores que a melhor forma de aumentar a produtividade era a reutilização do software
Os tipos abstratos de dados eram as unidades a serem reutilizadas
HERANÇA II A reutilização origina duas questões:
Quase sempre, os recursos do tipo já existente não são adequados ao novo emprego, e o modificador precisaria entender todo o código existente e alterar os clientes
Como definidos até aqui, os tipos de dados abstratos são independentes e estão no mesmo nível, o que torna impossível estruturar um problema
A herança fornece solução para as duas questões acima
HERANÇA - solução para o problema da modificação
Um novo tipo de dados abstrato pode herdar dados e funcionalidades de um tipo existente
Também é permitido modificar algumas entidades e adicionar novas
Exemplo: suponhamos que o tipo array, além de ter um método de classificação, necessite agora de método para computar sua mediana
Em vez de modificar a implementação do tipo existente, pode-se definir uma subclasse que retém a classificação e adiciona a si a computação da mediana
NOMENCLATURA Uma classe definida pela herança de outra é chamada
classe derivada ou subclasse A classe da qual a nova é derivada chama-se classe-pai ou
superclasse ou classe-raiz As chamadas a métodos frequentemente são chamadas de
mensagens A coleção de métodos de um objeto é o protocolo de
mensagem ou interface de mensagem do objeto Toda mensagem tem duas partes: o objeto específico ao
qual ela está sendo enviada e o nome de um método que define a ação solicitada no objeto
Computações podem ser vistas como mensagens enviadas
de objetos a outros objetos
AS CLASSES DERIVADAS COMO CLIENTES
O acesso a um membro de uma classe pode ser "concedido" ou "reusado"
Uma terceira categoria de acesso, com frequência chamada protected, é usada para fornecer concessão a uma classe derivada
SOBREPOSIÇÃO DE MÉTODOS
Um método modificado numa classe derivada tem o mesmo nome e muitas vezes o mesmo protocolo do método original
O novo método fica sobreposto ao original Objetivo da sobreposição: fornecer operação
específica a objetos da classe derivada, que não é apropriada para objetos da classe-pai
Exemplo: classe raiz French_Gothic com método draw, classes derivadas Reims, Amien e Chartres com métodos draw herdados e sobrepostos ao da classe raiz
HERANÇA SIMPLES E HERANÇA MÚLTIPLA
Se a classe derivada possui uma única classe-pai, o processo chama-se herança simples
Caso contrário (duas ou mais classes-pai), chama-se herança múltipla
"Hierarquia de classes" = conjunto de heranças em sua totalidade
Hierarquia de heranças simples gera uma árvore de derivação
Hierarquia de heranças múltiplas gera um grafo (direcionado) de dependências
HERANÇA SIMPLES E HERANÇA MÚLTIPLA II
Exemplo: um applet do Java com animação
os applets são suportados pela classe Applet
a concorrência (necessária para a animação) é suportada pela classe Thread
é necessário que um applet herde de ambas as classes
HERANÇA SIMPLES E HERANÇA MÚLTIPLA III
Desvantagem da hierarquia: dependência entre as classes (os tipos de dados abstratos perdem sua independência...)
Porém: é impossível reusar tipos sem criar dependências entre alguns deles
HERANÇA SIMPLES E HERANÇA MÚLTIPLA IV Problema da colisão de nomes: se a subclasse
C herdar tanto de A como de B, e ambas incluem a variável hereditária sum, como C poderá referir-se às duas sum diferentes?
Problema da herança diamante: suponha também que A e B sejam subclasses de Z
Não está claro ainda se os benefícios da herança múltipla valem o esforço adicional de gerenciar o intrincado complexo de dependências...
HERANÇA EM C++: Exemplo
class classe_base{private:
int a; float x;protected:
int b; float y;public:
int c; float z;};
class subclasse_1: public classe_base{...}class subclasse_2: private classe_base{...}
DISCUSSÃO DO EXEMPLO ANTERIOR
Observe a existência de um modo de acesso na definição das subclasses
É claro que a,x não são visíveis em qualquer descendente de classe_base
subclasse_1 mantém b,y como protegidos e c,z como públicos
Em subclasse_2 b,y,c,z são todos membros privados Nenhuma classe derivada de subclasse_2 pode ter
acesso a qualquer membro de dados de classe_base Isto é, uma subclasse private X interrompe o acesso de
suas descendentes aos membros de dados dos
ancestrais de X
HERANÇA EM C++: outro exemplo
class lista_encadeada{class lista_encadeada{
class no{class no{
friend class lista_encadeada;friend class lista_encadeada;
private:private:
int info;int info;
no *prox;no *prox;
}}
private: private:
no *inicio;no *inicio;
public:public:
lista_encadeada ( ) {inicio=0};lista_encadeada ( ) {inicio=0};
void insere_inicio(int);void insere_inicio(int);
void insere_final(int);void insere_final(int);
int remove_inicio( );int remove_inicio( );
int vazia( );int vazia( );
};};
HERANÇA EM C++: outro exemplo II
class pilha : public lista_encadeada{class pilha : public lista_encadeada{
public:public:
pilha( ) { }pilha( ) { }
void push (int elem){void push (int elem){
lista_encadeada::insere_inicio(int elem);lista_encadeada::insere_inicio(int elem);
}}
void pop ( ) {void pop ( ) {
return lista_encadeada::remove_inicio( );return lista_encadeada::remove_inicio( );
}}
};};
HERANÇA EM C++: outro exemplo III
class fila : public lista_encadeada{class fila : public lista_encadeada{public:public:
fila( ) { }fila( ) { }void enqueue (int elem){void enqueue (int elem){
lista_encadeada::insere_final(int elem);lista_encadeada::insere_final(int elem);}}int dequeue ( ) {int dequeue ( ) {
return lista_encadeada::remove_inicio( return lista_encadeada::remove_inicio( ););
}}};};
HERANÇA MÚLTIPLA EM HERANÇA MÚLTIPLA EM C++C++
class A {...}class A {...}
class B {...}class B {...}
class C: public A, public B {...}class C: public A, public B {...}
:: -> operador de resolução de escopo (solução C++ para o conflito de nomes em herança múltipla )
REEXPORTAÇÃO
class subclasse_3 : private classe_base{
classe_base :: c; // c passa a ser visível em // descendentes de
//subclasse_3...}
:: -> operador de resolução de escopo
POLIMORFISMO E VINCULAÇÃO DINÂMICA Variáveis polimórficas: são do tipo da classe-pai e
também podem referenciar objetos de qualquer uma das subclasses da mesma
Variáveis polimórficas são ponteiros ou referências Considere um método M sobreposto nas subclasses Quando M é invocado por uma variável polimórfica,
esta chamada é vinculada dinamicamente ao método da classe apropriada
Isto permite a extensão e a manutenção de sistemas com muito mais facilidade
POLIMORFISMO E VINCULAÇÃO DINÂMICA II
Exemplo: variável polimórfica cathedral do tipo French_Gothic pode referenciar os métodos draw de Reims, Amien e Chartres.
Quando cathedraw for usada para chamar draw, esta chamada será vinculada dinamicamente à versão correta de draw
O MESMO EXEMPLO EM C...
Se o exemplo das catedrais fosse escrito em C, os três tipos de catedrais poderiam estar um struct
Haveria uma única função draw que usaria uma instrução switch, do seguinte modo: um parâmetro por valor seria enviado a draw para especificar qual item do switch contém as diretivas de desenho corretas
Se adicionarmos uma nova catedral do tipo Paris, temos que modificar o switch e repensar o protocolo de draw
Com orientação a objetos, basta criar uma nova subclasse com seu método sobreposto. Não há
necessidade de alterar o código existente
QUANDO A HIERARQUIA CRESCE...
Às vezes a classe-raiz está tão alta e tão distante na hierarquia que nem faz sentido instanciá-la num objeto particular
Exemplo: suponha que Building seja classe-pai de French_Gothic. Building é um tipo "edifício genérico"
Talvez não faça sentido um método draw em Building Mas como todas as suas classes descendentes tem este
método implementado, o protocolo (mas não o corpo) deste método é incluído em Building
Este método abstrato é chamado método virtual A classe Building é chamada classe virtual - não pode ser
instanciada, porque nem todos os seus métodos têm corpos
POLIMORFISMO EM C++class Building { // classe "abstrata" (virtual) public:
virtual void draw( ) = 0; // função virtual "pura" ...}
class French_Gothic : public Building {public:
virtual void draw( ) {...} // método sobreposto...}
class German_Gothic : public Building {public:
virtual void draw( ) {...} // método sobreposto ...}
POLIMORFISMO EM C++ IIFrench_Gothic x;German_Gothic y;
Building &ref_build = x; // ref_build é polimórfica // e faz referência a uma
// catedral francesa
ref_build.draw( ); // vinculado dinamicamente ao draw // para catedral francesa
y.draw( ); // vinculado estaticamente ao draw // para catedral alemã
É claro que a vinculação estática, apesar de menos flexível, é mais eficiente que a dinâmica
POLIMORFISMO E VERIFICAÇÃO DE TIPOS
Quando o método sobreposto chamado é vinculado ao método correto, deve-se checar se:
os tipos dos parâmetros reais na mensagem coincidem com os parâmetros formais do método correto
o tipo do valor de retorno do método correto é o tipo esperado da mensagem
Se a vinculação for dinâmica, a verificação deverá ser retardada até o ponto da execução
em que a mensagem é enviada
MODELO DE COMPUTAÇÃO
PURAMENTE OO
É uma técnica uniforme: enviar uma mensagem a um objeto para invocar um de seus métodos
A resposta à mensagem é um objeto que retorna o valor da computação do método
Os objetos podem ser vistos como uma coleção de computadores que se comunicam entre si pelas mensagens (modelo abstrato de computação distribuída)
MODELO DE COMPUTAÇÃO
PURAMENTE OO II
Cada objeto é a abstração de um computador com seus dados (sua memória local) e sua capacidade de processamento (seus métodos)
Podemos então simular o problema real identificando os objetos do mundo real, seus processos e as comunicações necessárias entre eles
MODELO DE COMPUTAÇÃO
PURAMENTE OO III Tudo é objeto - desde o menor número
inteiro até um sistema complexo de dados e processos
Todos os tipos são classes Toda a computação é a invocação de um
método. Exemplo: 21 + 2 Não há distinção entre classes predefinidas
e classes definidas pelo usuário - todas são tratadas da mesma maneira
MODELO DE COMPUTAÇÃO
PURAMENTE OO IV
A vantagem é a uniformidade, a elegância, a maleabilidade do uso
Desvantagem: tudo deve ser feito pelo processo de passagem de mensagens, o que torna as operações mais lentas em relação às suas similares imperativas
Smalltalk: chega a ser comercialmente inviável pela sua baixíssima eficiência
ALTERNATIVAS À COMPUTAÇÃO PURAMENTE
OO
Alternativa I: manter um modelo completo de tipificação imperativo e simplesmente adicionar o modelo OO
Porém: a estrutura de tipos fica extremamente confusa (C++...)
Alternativa II: manter o modelo imperativo apenas para tipos primitivos escalares
Necessidade das classes wrapper (envoltórias) sobre tipos não-objeto (Java...)
SUBCLASSES SÃO SUBTIPOS?
Exemplo: Ada subtype SMALL_INT is INTEGER range -
100..100 Para todos os efeitos, SMALL_INT é uma
variável INTEGER Usa as mesmas operações e pode aparecer
no lugar de qualquer variável INTEGER Uma classe é chamada subtipo se guardar
as mesmas características acima com sua classe-pai
SUBCLASSES SÃO SUBTIPOS? II
Para ser subtipo, a subclasse deve: herdar "tudo" adicionar/sobrepor métodos de modo
"compatível" (sem causar erros de tipo) a sobreposição segura pode ser
garantida usando exatamente o mesmo protocolo
mas há restrições menos severas...
OCULTAÇÃO DA INFORMAÇÃO ÀS
SUBCLASSES
A implementação da classe fica oculta aos clientes
E com relação às subclasses? Herança de interface = apenas a
interface da classe pai é visível à subclasse
Herança de implementação = os detalhes da implementação também são visíveis na subclasse
OCULTAÇÃO DA INFORMAÇÃO ÀS SUBCLASSES II
Exemplo: subclasse da classe pilha que deve ter um método para retornar o elemento logo abaixo do topo
com herança de implementação, basta verificar ptr_pilha [top_ptr-1]
com herança de interface: int segundo( ){ ...
int temp = top( );pop( );int result_temp = top( );push(temp);return result_temp;
}
COMENTÁRIOS GERAIS AO C++
Compatibilidade quase completa com C (questão de projeto)
Híbrido no sentido de que possui tanto os tipos das linguagens imperativas tradicionais como a estrutura de classes da OO
Suporta tanto programação orientada a procedimentos como a objetos
COMENTÁRIOS GERAIS AO C++ II
Objetos podem ser alocados nos mesmos lugares onde se aloca variáveis no C
Objetos dinâmicos devem ser explicitamente desalocados com delete
Não há reivindicação de armazenamento implícita
C++ não está imune ao problema das referências oscilantes e do vazamento de memória...
Com a desvantagem de que os ponteiros agora são para objetos!
COMENTÁRIOS GERAIS AO C++ III
Todas as classes incluem pelo menos um método construtor, utilizado para inicializar os membros de dados
Métodos construtores são chamados implicitamente na criação do objeto
Se nenhum construtor é incluído na definição da classe, o compilador incluirá um método construtor trivial
COMENTÁRIOS GERAIS AO C++ IV
O destrutor é implicitamente chamado quando o objeto deixa de existir
Desalocação de membros de dados dinâmicos devem estar presentes no destrutor!
Herança do C++ é confusa em relação ao Smalltalk em termos de controle de acesso
Levando também em consideração as declarações friend, o programador C++ tem um controle altamente detalhado (e complicado!) do acesso aos membros
Questiona-se se isto é produtivo...
COMENTÁRIOS GERAIS AO C++ V
Em C++ o programador pode especificar vinculação estática ou dinâmica
A vinculação dinâmica em C++, apesar de mais lenta que a estática, tem um acréscimo de custo fixo, mesmo que a mensagem seja vinculada a um método distante na hierarquia.
Em Smalltalk, as mensagens são sempre vinculadas dinamicamente a métodos e o custo da vinculação depende da distância na hierarquia
COMENTÁRIOS GERAIS AO C++ VI
A possibilidade de verificação estática de tipos em C++ é vantajosa
As classes genéricas possibilitam verificação estática
Em Smalltalk, toda verificação é dinâmica. Pode-se até chamar métodos não existentes, e isto só será notado na execução
COMENTÁRIOS GERAIS AO C++ VII
Smalltalk é totalmente dedicada ao paradigma OO, ignorando imposições de bases guerreiras de usuários
Smalltalk é uma linguagem pequena, elegante, altamente simples e ortogonal
C++ é uma linguagem grande, complexa e sem filosofia particular como base, exceto a de incluir usuários de C
COMENTÁRIOS GERAIS AO C++ VIII
Alguns acham que os recursos de C++ nem sempre se encaixam bem sobre o C
Testes revelam que Smalltalk compila a 10% da velocidade de um compilador C otimizado
C++ compila exigindo somente um pouco mais de tempo que os compiladores C
Dada a grande distância de eficiência entre C++ e Smalltalk, é fácil explicar a diferença de sucesso comercial entre as duas
Além disso, há a "compatibilidade" de C++ com a base usuária C