Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


P. o o orientada, Notas de estudo de Engenharia Elétrica

Introdução à Programação Orientada a Objetos Usando Java

Tipologia: Notas de estudo

2011

Compartilhado em 31/03/2011

leonardo-lira-1
leonardo-lira-1 🇧🇷

5

(1)

13 documentos

1 / 30

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
PROGRAMAÇÃO
ORIENTADA
A
OBJETOS
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e

Pré-visualização parcial do texto

Baixe P. o o orientada e outras Notas de estudo em PDF para Engenharia Elétrica, somente na Docsity!

PROGRAMAÇÃO

ORIENTADA

A

OBJETOS

    1. INTRODUÇÃO
    • 1.1 UM BREVE HISTÓRICO DE LINGUAGENS DE PROGRAMAÇÃO
    • 1.2 PROGRAMAÇÃO ORIENTADA A OBJETOS
    1. CLASSE
    • 2.1 ATRIBUTOS
    • 2.2 MÉTODOS
    1. OBJETOS
    1. MENSAGENS
    1. ENCAPSULAMENTO
    1. HERANÇA
    1. POLIMORFISMO
    • 7.1 Definição:
    • 7.2 Tipos Clássicos de Polimorfismo:
    1. LATE BINDING
    • 8.1 Definição
    • 8.2 Tipos
    • 8.3 Ligação Precoce e Tardia (O. O.)
      • 8.3.1 Dynamic Typing E Dynamic Binding - O.O.
    • 8.4 Conclusões
    1. BIBLIOGRAFIA

As idéias de Simula serviram de base para as propostas de utilização de Tipos Abstratos de Dados, e também para Smalltalk. Smalltalk foi desenvolvida no Centro de Pesquisas da Xerox durante a década de 70, e incorporou, além das idéias de Simula, um outro conceito importante, devido a Alan Kay, um de seus idealizadores: o princípio de objetos ativos, prontos a “reagir” a “mensagens” que ativam “comportamentos” específicos do objeto. Ou seja, os objetos em Smalltalk deixam de ser meros “dados” manipulados por “programas”, e passam a ser encarados como “processadores idealizados” individuais e independentes, aos quais podem ser transmitidos comandos em forma de “mensagens”.

Outras linguagens orientadas para objetos tem sido desenvolvidas. Notadamente C++, uma extensão de C, Objetive-C, outra extensão de C, menos popular que a anterior, Pascal orientado a objetos, Eiffel e mais recentemente, no Brasil, TOOL.

Além da Xerox, que criou a ParcPlace Systems especialmente para comercializar Smalltalk-80 e seus sucedâneos (objectWorks), a Digitalk lançou em 1986 uma versão de Smalltalk para ambiente DOS, e mais recentemente a versão para Windows, o que contribuiu para uma maior difusão da linguagem [Digitalk].

Smalltalk, uma das mais populares linguagens orientadas a objetos, assim como outras linguagens orientadas para objetos, tem sido usada em aplicações variadas onde a ênfase está na simulação de modelos de sistemas, como automação de escritórios, animação gráfica, informática educativa, instrumentos virtuais, editores de texto e bancos de dados em geral, entre outras. Tais aplicações diferem substancialmente daquelas em que a ênfase está na resolução de problemas através de algoritmos, tais como problemas de busca, otimização e resolução numérica de equações. Para essas aplicações, é mais adequado o uso de linguagens algorítmicas convencionais, como Pascal, Algol e Fortran.

1.2 PROGRAMAÇÃO ORIENTADA A OBJETOS

Uma das atividades mais interessantes em Informática é certamente a busca constante de melhorias nas linguagens e técnicas para o desenvolvimento de software. Desta busca decorrem as transformações e evoluções das linguagens de programação, surgindo novas linguagens e novos paradigmas.

A Programação Orientada a Objetos utiliza os conceitos que aprendemos no jardim de infância: objetos e atributos, todos e partes, classes e membros. É difícil explicar por que demoramos tanto a aplicar estes conceitos à análise e especificação de sistemas de informações

  • talvez porque estivéssemos ocupados demais “seguindo a boiada” durante o auge da análise estruturada para imaginar que havia alternativas.

A Enciclopédia Britânica afirma: Na compreensão do mundo real, as pessoas empregam constantemente três métodos de organização, sempre presentes em todos os seus pensamentos:


(1) Diferenciação, baseado na experiência de cada um, de objetos particulares e seus atributos - quando distinguem uma árvore, e seu tamanho ou relações espaciais, dos outros objetos, (2) Distinção entre objetos como um todo e entre suas partes componentes - por exemplo, quando separam uma árvore dos seus galhos, e (3) Formação de, e distinção entre, as diferentes classes de objetos - por exemplo, quando formam uma classe de todas as árvores, uma outra classe de todas as rochas e distinguem-nas. A Programação Orientada a Objetos se apóia nestes três métodos usuais de organização.

Programação Orientada a Objetos é a programação implementada pelo envio de mensagens a objetos. Cada objeto irá responder às mensagens conhecidas por este, e cada objeto poderá enviar mensagens a outros, para que sejam atendidas, de maneira que ao final do programa, todas as mensagens enviadas foram respondidas, atingindo-se o objetivo do programa. Programação Orientada a Objetos, técnicas e artefatos ditos “orientados a objetos” incluem linguagens, sistemas, interfaces, ambientes de desenvolvimento, bases de dados, etc.

No entanto, cabe ressaltar que o conceito de Orientação Objeto depende mais da mentalidade do programador do que da linguagem de programação que está sendo utilizada. Pode-se conseguir programas razoavelmente orientados a objeto em linguagens tipicamente estruturadas, assim como pode-se conseguir programas estruturados em linguagens voltadas para objetos. Tomemos como exemplo a frase:

“O navio atraca no porto e descarrega sua carga.”

se analisássemos esta frase estruturadamente, pensaríamos logo em como o navio atraca no porto e como ele faz para descarregar sua carga, ou seja, pensaríamos na ação que está sendo feita (que na frase é representada pelos verbos) para transformá-la em procedimento. Em orientação objeto, o enfoque com que se encara a frase é diferente: primeiro pensaríamos no objeto navio, no objeto porto e no objeto carga, pensando como eles seriam e procurando definir seu comportamento. Após isto é que pensaremos em como o navio se relaciona com o porto e com a carga, e como o porto se relaciona com carga. De modo grosseiro, podemos dizer que ao analisarmos uma frase pensando estruturadamente, damos ênfase aos verbos, e pensando orientado a objetos, damos ênfase aos substantivos.

Pelo que foi visto acima, percebe-se que o programador experiente terá inicialmente grande dificuldade em migrar para a orientação a objeto, pois terá que esquecer os anos de prática analisando os problemas estruturadamente, para reaprender a analisá-los de forma voltada a objeto. Ninguém faria isto se não tivesse bons motivos. Abaixo são mostradas algumas das vantagens que motivam veteranos programadores a readaptar-se para o paradigma de orientação a objeto:

? ?Sensível redução no custo de manutenção do software ? ?Aumento na reutilização de código


permitirão um melhor entendimento do assunto. Nas páginas seguintes abordaremos os conceitos básicos do Paradigma de Orientação a Objetos: Objetos, Classes, Mensagens, Métodos, Herança, Generalização, Especialização, Abstração, Polimorfismo, Encapsulamento e Late-Binding. Conheceremos suas definições conceituais, como podem ser aplicados, quando devem ser utilizados e principalmente por que devemos usar estes conceitos e quais são suas vantagens e desvantagens sobre a programação estruturada.

2. CLASSE

Classe é o termo técnico utilizado em linguagens orientadas a objetos que descreve um conjunto de dados estruturados que são caracterizados por propriedades comuns. Também pode ser interpretado como uma estrututura modular completa que descreve as propriedades estáticas e dinâmicas dos elementos manipulados pelo programa.

Pode-se definir classes de objetos como a descrição de um grupo de objetos por meio de um conjunto uniforme de atributos e serviços. Uma classe é um conjunto de objetos que compartilham as mesmas operações.

Enquanto um objeto individual é uma entidade concreta que executa algum papel no sistema como um todo, uma classe captura a estrutura e o comportamento comum a todos os objetos que são relacionados. Um objeto possui uma identidade e suas características serão definidas para a classe.

Uma classe é definida por:

?? um nome da classe; ?? o nome da sua superclasse; ?? o nome de suas variáveis privadas; ?? os nomes e as definições de todas as operações associadas a esta classe;

Classe é um conceito estático: uma classe é um elemento reconhecido num texto de programa. por outro lado, um objeto é um conceito puramente dinâmico, o qual pertence não ao texto do programa, mas à memória do computador, local onde os objetos ocupam espaço durante a execução. (Conceitualmente, classes não são necessárias durante a execução, mas em linguagens interpretadas elas podem ser mantidas).

Exemplo de classe:

Uma classe é semelhante a uma struct e em C++ podemos definir a classe fila do seguinte modo:

class fila { int f [100]; int primeiro, ultimo;


public:

void inicio (void); void put (int valor); int get (void)

};

Examinando a declaração anterior, vemos: Uma classe pode contertanto partes públicas como privadas. Por exemplo, as variáveis f , primeiro e ultimo são privadas. Isto significa que não podem ser acessadas por qualquer função que nao seja membro dessa classe.

Para tornar públicas as partes de uma classe, ou seja, acessíveis o outras partes do programa, é preciso declará-las após a palavra public.

2.1 ATRIBUTOS

Um atributo é um dado para o qual cada objeto tem seu próprio valor.

Atributos são, basicamente, a estrutura de dados que vai representar a classe.

Exemplo de atributos, usando a classe fila :

int f [100] ; int primeiro, ultimo;

2.2 MÉTODOS

Métodos são declarados dentro de uma classe para representar as operações que os objetos pertencentes a esta classe podem executar.

Um método é a implementação de uma rotina, ou seja, o código propriamente dito. Pode ser comparado a um procedimento ou função das linguagens imperativas.

Exemplo de métodos, utilizando a classe fila :

void iniciar (void) { primeiro = 0; ultimo = 0; };


tamanho horizontal tamanho vertical paleta de cores cor atual métodos modo texto ( ) modo gráfico ( ) fecha modo gráfico ( ) muda cor ( ) escreve caracter ( ) coloca pixel ( ) muda dimensões (x,y) ...

Um guarda-roupa:

estrutura conjunto de roupas /* tipo, tamanho, cor, estilo, preço, etc. */ portas número de portas capacidade máxima

métodos abre porta ( ) fecha porta ( ) escolhe roupa ( ) tira roupa ( ) coloca roupa ( ) estado do guarda-roupa ( ) /* portas abertas e fechadas, quantidade de roupas, etc. */ ...

Uma lista:

estrutura (nodo e um apontador para um próximo nodo) Primeiro e atual

métodos cria lista ( ) /* cria célula cabeça e inicializa / próximo ( ) /vai para o próximo elemento da lista / insere ( ) / insere um elemento na posição atual / deleta ( ) / apaga posição atual / volta ao começo ( ) / atual = primeiro */ ...


Podemos notar que um objeto é composto por estrutura e processos, onde esses processos giram em torno da estrutura, ao contrário das linguagens funcionais, nas quais a estrutura se adapta a função. Um objeto só pode ser manipulado por sua estrutura e seus métodos, nada mais do que isso. Somente um objeto de um determinado tipo pode acessar seus métodos e estrutura, um outro tipo de objeto não tem nenhum acesso a estes. Por exemplo, em uma classe cachorro temos o método fala. Se por exemplo definirmos um objeto da classe gato, este objeto não tem acesso nenhum ao método fala de cachorro.

Dentro de um objeto, alguns métodos e/ou estrutura podem ser privados ao objeto, o que nos diz que são inacessíveis diretamente para qualquer elemento fora dele, o que impede que outros objetos tenham acesso direto às partes privadas do objeto referenciado. Para o objeto poder referenciar seus elementos privados ele deve passar pelos seus métodos, neste caso um método específico que faça a operação desejada, ou seja, ele pode acessar sua estrutura privada somente através de seus métodos, dando assim uma certa abstração de como é feita a manipulação da estrutura. Isso consiste no encapsulamento de dados que será explicado na seção referente a este tema. A princípio toda a estrutura deve ser privada, mas algumas linguagens como C++ permitem que a estrutura de um objeto possa ser acessada diretamente por outros objetos. Já em SmallTalk toda a estrutura é privada. Dessa maneira, um objeto evita significativamente que algumas outras partes não relacionadas de programa modifiquem ou usem incorretamente as partes privadas do objeto referenciado, dando assim maior confiabilidade na manipulação do objeto. Isso tudo nos mostra uma característica muito grande para construção de módulos independentes e abstração ao usuário. Mais exatamente, cada objeto é uma instância de sua classe. É a classe que contém a descrição da representação interna e dos métodos comuns a todas as suas instâncias (objetos). Cada instância da classe, por sua vez, possui sua própria memória privativa (seu estado interno) onde ficam armazenados os valores de seus componentes, que representam suas características individuais. Associando com a linguagem C, uando você define uma estrutura como por exemplo:

struct aluno { char nome [30]; char telefone [20]; int número; };

Quando você declara uma variável do tipo struct aluno você define uma instância da estrutura aluno.

main ( ) { struct aluno a; /* a é uma variável do tipo da estrutura aluno */ ... }


não é uma característica somente de orientação a objetos. Garbage Collection consiste em eliminação pelo compilador do objeto/variável depois de sua última utilização. A partir do momento em que ele não é mais referenciado, passa a não existir mais na memória. Por exemplo, Garbage Collection é implementado em Lisp e SmallTalk enquanto que em C++ e Pascal não. Quando o objeto é eliminado ele automaticamente executa seu destrutor.

Em programação orientada a objetos, primeiramente o que deve ser identificado são os objetos que o problema requer (até mesmo os tipos simples de dados são vistos como objetos, porque têm estrutura e operações (métodos) que o manipulam). Por exemplo um objeto inteiro é comparado com outro, recebe uma atribuição, tem operações aritméticas. Esta nova concepção não é tão fácil de ser encarada, principalmente para quem já é experiente em programação imperativa. As principais dificuldades a princípio são a identificação dos objetos, e o tratamento do problema somente através de objetos.

4. MENSAGENS

Mensagens são requisições para que um objeto execute uma de suas ações. Cada objeto somente pode responder às mensagens que constem do seu protocolo. O protocolo de um objeto são as mensagens correspondentes as suas operações, além do protocolo de sua superclasse.

Os objetos interagem através de mensagens.

O atendimento de uma mensagem envolve a execução de algum tipo de código, ou seja, os métodos, sobre um dado associado àquela operação, ou seja, sobre os atributos.

Quando um objeto é criado, o acesso a suas características é feito através de mensagens. Para cada mensagem recebida pelo objeto, existe um método associado para respondê-la. Quando a mensagem estiver se referenciando a um atributo, o valor deste deve ser devolvido, e no caso de uma operação, o procedimento desta é executado.

As operações podem ter parâmetros de entrada e saída com tipos determinados. Esta característica, juntamente com o seu nome, definem a assinatura de uma mensagem.

Exemplo de mensagem, utilizando a classe fila :

seja a declaração de um objeto:

fila fila_atual; . . . A mensagem a este objeto seria:


fila_atual.get( );

5. ENCAPSULAMENTO

O conceito de encapsulamento é decorrente do fato de se combinar os dados ( atributos ) e o código que manipula estes dados ( métodos ) em um único Objeto. Ele garante que a única forma de acesso aos dados é através dos métodos disponíveis ao usuário (chamados públicos ). Os demais métodos e os atributos da classe ficam sendo privados , ou seja, apenas funções-membro da classe têm acesso direto aos mesmos.

Objeto atributos métodos Aplicação

O conceito de encapsulamento não é exclusivo do paradigma de Orientação a Objetos. Ele já era utilizado na definição de Tipos Abstratos de Dados, para dizer que os dados só deveriam ser manipulados pelas funções que compunham o TAD.

Trocando em miúdos, o encapsulamento diz respeito à definição de uma estrutura que contenha os dados, defina quais os métodos de acesso público a esses dados e possua meios de proteger os demais métodos e os dados contra acesso direto.

Mas... por que impedir este acesso?

Responderemos esta pergunta com um exemplo prático. Imaginemos um objeto Polinômio. Vamos supor que a estrutura de dados utilizada para representar um polinômio dentro do objeto seja um vetor. Este objeto, quando criado, recebe um string contendo o polinômio que ele representará (por exemplo, “x^2 + 2x +10”) e possui, entre outros, um método para, dado um x , calcular f(x).


mesma e perdesse algum dado. O encapsulamento protege os dados, e faz o uso do objeto ser mais seguro.

Em outras palavras, o Encapsulamento garante que a minha classe seja uma caixinha preta para o usuário: ele não sabe o que há dentro do objeto, sabe apenas para que ele serve e quais os métodos disponíveis para a manipulação deste.

Note-se que este conceito possui efeito contrário para um objeto mal definido. Se, ao projetarmos uma classe, não fornecemos métodos de acesso adequados, teremos dificuldades em criar aplicações eficientes com objetos instanciados da mesma. Por exemplo, a nossa classe polinômio deveria possuir um método para informar se um termo de ordem n está presente no objeto. Caso contrário, fica difícil, por exemplo, implementar uma aplicação que compare dois polinômios e diga se possuem todos os termos de ordens iguais ( ex.: x^2 + 2 e 3x^2 + 5).

Logo, a tarefa de projetar uma classe envolve, entre outras atividades, definir da melhor maneira possível quais métodos de acesso ao objeto serão disponibilizados ao usuário. Um bom projeto inicial evita a necessidade de se redefinir uma classe já implementada.

6. HERANÇA

Herança é a propriedade dos objetos que permite a criação de uma hierarquia entre eles, onde os descendentes herdam o acesso ao código e estruturas de dados dos seus ancestrais.

Coad-Yourdon define Herança como: Mecanismo para expressar a similaridade entre classes, simplificando a definição de Classes similares a outras que já foram definidas. Ela representa generalização e especialização, tornando atributos e serviços comuns em uma hierarquia de Classe.

Para entender o significado dessa definição, usaremos um exemplo simples. Digamos que eu tenha uma classe Animal. Todos os objetos da classe Animal possuem características (atributos) comuns, como peso, altura, idade, estados como ter fome, etc. Também fazem determinadas tarefas (serviços ou métodos) como Comer, Procriar, Nascer, Morrer, se movimentar, etc. Eu posso abstrair esse objeto Animal para reduzi-lo à seguinte representação:

class Animal { int Peso, Altura, Idade; boolean EstaComFome; public: Animal( ) { ... } /* Construtor */ ~Animal( ) { ... } /* Destrutor */ boolean ComFome( ); int Peso( ); int Altura( );


Muito bem, então eu defini minha classe Animal e a usei no meu aplicativo. Digamos que a classe foi projetada e implementada de uma maneira ótima, que possui todos os atributos e classes necessárias para a representação de um animal qualquer.

Digamos que eu tenha mais um aplicativo para fazer, que precise de uma Classe Mamífero. A representação de um mamífero é muito parecida com a de um Animal, mas ele possui atributos e métodos que não são comuns a todos os animais: mamíferos (mamar, emitir sons etc.), além de fazerem algumas atividades de forma diferente dos demais Animais (Nem todos os animais comem ou procriam como os mamíferos, por exemplo).

Numa linguagem de programação sem herança, a implementação da classe Mamífero provavelmente implicaria na replicação do código de Animal, com as modificações necessárias para caracterizar a classe. Se fosse necessário implementar uma classe Macaco, eu replicaria o código de Mamífero na nova classe. Uma classe Chimpanzé teria o código de Macaco replicado em si, e assim sucessivamente.

Isso não está bom. Se fosse necessário implementar todas as classes existentes entre o Ser Vivo e o Mosquito, teríamos centenas de classes, todas com replicação do código das classes anteriores. Além disso, se houvesse a necessidade de modificar algum método de Animal que fosse comum a todas estas centenas de classes, esta modificação teria que ser feita em todas elas, uma a uma. Será que não existe uma maneira melhor?

Na verdade, é fácil perceber que Mamífero é na verdade uma especialização de Animal , um herdeiro dessa classe. Assim, se eu dispuser de um mecanismo que me permita declarar Mamífero como tal, e assim herdar todos os métodos e atributos da classe ancestral, não precisarei replicar código, apenas incluirei os métodos e atributos específicos na classe Mamífero, e redefinirei os métodos que achar necessário. O mecanismo que me permite isso é a Herança.

A Herança vai produzir uma ordem de hierarquia entre as diversas Classes-Objetos que estiverem relacionadas desta forma. Um objeto herdeiro é em geral uma especialização do seu ancestral, que por conseqüência será uma generalização de seu sucessor. Eu posso montar uma estrutura de hierarquias entre Classes-Objetos baseada na relação generalização- especialização, resultando que os objetos mais ancestrais são mais genéricos ou abrangentes, e os seus sucessores são cada vez mais específicos, à medida que nos aprofundamos na estrutura. Observe como eu posso montar uma estrutura desse tipo baseado na classe Animal:

Animal

Mamífero Peixe


Uma classe pode ser herdeira direta de mais de uma classe ao mesmo tempo. Isto é chamado de Herança Múltipla. A herança múltipla se aplica em situações como a do golfinho. Ele é um mamífero, mas possui características de Peixe. Assim, fazemos a classe Golfinho herdar de Peixe e Mamífero, e redefinimos os métodos específicos para Golfinho.

Animal

Mamífero Peixe

Golfinho

É importante ressaltar que normalmente não é preciso redefinir os métodos, e atributos herdados não precisam ser redeclarados ou redefinidos, a não ser que haja necessidade de refiná-los. Por exemplo, Antropóide e Homem respiram do mesmo jeito, logo eu vou utilizar o método Respira( ) de Antropóide para fazer Homem respirar. Entretanto Os mamíferos andam de formas diferentes, logo um método Anda( ) em Mamífero provavelmente terá que ser redefinido para Antropóide e Elefante, por exemplo. A principal vantagem da herança em linguagens Orientadas a Objeto está no reaproveitamento de código que ela proporciona, pela declaração de classes herdeiras mais específicas ao meu problema. Do ponto de vista da Análise Orientada a Objetos, a herança permite uma melhor organização dos elementos que envolvem o Domínio do Problema, facilitando a compreensão do mesmo e a procura de soluções adequadas para o Sistema em questão.

A estrutura dos exemplos acima poderia ser implementada em C++ desta forma:

class Mamifero: public Animal {

boolean querMamar;

public: Mamífero( ):Animal( ) {} ~Mamífero( ); void Mamar( ); void Respirar( ); ... }

class Elefante: public Mamifero { public: Elefante( ):Mamífero( ) {}


~Elefante( ); void LevantarTromba( ); void Andar( ); ... }

class Antropoide: public Mamifero { public: Antropoide( ):Mamifero( ) {}; ~Antropoide( ); void Andar( ); void Procriar( ); ... }

class Homem: public Antropoide { public: Homem( ):Antropoide( ) {}; ~Homem( ); void Fala( ); ... }

class Macaco: public Antropoide { public: Macaco( ):Antropoide( ) {}; ~Macaco( ); void SobeNaArvore( ); ... }

class Peixe: public Animal { int número_de_escamas; public: Peixe( ):Animal( ) {}; ~Peixe( ); void Nadar( ); void Comer( ); ... }

class Tubarao: public Peixe { public: Tubarao( ):Peixe( ) {};