440 likes | 532 Views
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.
E N D
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_Gothiccom 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_2b,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 Xinterrompe o acesso de suas descendentes aos membros de dados dos ancestrais de X
HERANÇA EM C++: outro exemplo class lista_encadeada{ class no{ friend class lista_encadeada; private: int info; no *prox; } private: no *inicio; public: lista_encadeada ( ) {inicio=0}; void insere_inicio(int); void insere_final(int); int remove_inicio( ); int vazia( ); };
HERANÇA EM C++: outro exemplo II class pilha : public lista_encadeada{ public: pilha( ) { } void push (int elem){ lista_encadeada::insere_inicio(int elem); } void pop ( ) { return lista_encadeada::remove_inicio( ); } };
HERANÇA EM C++: outro exemplo III class fila : public lista_encadeada{ public: fila( ) { } void enqueue (int elem){ lista_encadeada::insere_final(int elem); } int dequeue ( ) { return lista_encadeada::remove_inicio( ); } };
HERANÇA MÚLTIPLA EM C++ class A {...} class 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 switchconté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++ II French_Gothic x; German_Gothicy; 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