Programação Orientada a Objetos

O conceito de programação orientada por objetos não é novo. No final da década de 60, a linguagem Simula67, desenvolvida na Noruega, introduzia conceitos hoje encontrados nas linguagens orientadas a objetos. Em meados de 1970, o Centro de Pesquisa da Xerox (PARC) desenvolveu a linguagem Smalltalk, a primeira totalmente orientada a objetos. No início da década de 80, a AT&T lançaria a Linguagem C++, uma evolução da linguagem C em direção à orientação a objetos.

Atualmente, a grande maioria das linguagens incorpora características de OO, como Java e Object Pascal. Além das linguagens de programação, é possível encontrar o conceito de OO em sistemas operacionais, como no caso do Windows 2000, e em banco de dados, como no Oracle8 e, principalmente, Jasmine da CA.

A programação orientada a objetos tem como principais objetivos reduzir a complexidade no desenvolvimento de software e aumentar sua produtividade. A análise, projeto e programação orientadas a objetos são as respostas para o aumento da complexidade dos ambientes computacionais que se caracterizam por sistemas heterogêneos, distribuídos em redes, em camadas e baseados em interfaces gráficas.

A programação orientada a objetos não tem a intenção de substituir a programação estruturada tradicional. Podemos considerar que a programação OO é uma evolução de práticas que são recomendadas na programação estruturada, mas não formalizadas, como o uso de variáveis locais, visibilidade e escope. O modelo de objetos permite a criação de bibliotecas que tornam efetivos o compartilhamento e a reutilização de código, reduzindo o tempo de desenvolvimento e, principalmente, simplificando o processo de manutenção das aplicações.

A grande dificuldade para compreender a programação OO é a diferença de abordagem do problema. Enquanto a programação estruturada tem como principal foco as ações (procedimentos e funções), a programação OO se preocupa com os objetos e seus relacionamentos. Além do conceito de objeto, a programação OO tem como alicerces os conceitos de encapsulamento, classe, herança e polimorfismo.

Programação Orientada a Objetos Programação Estruturada
Métodos Procedimentos e funções
Instâncias de variáveis Variáveis
Mensagens Chamadas a procedimentos e funções
Classes Tipos de dados definidos pelo usuário
Herança -
Polimorfismo -

Um objeto é uma abstração de software que pode representar algo real ou virtual. Um objeto é formado por um conjunto de propriedades (variáveis) e procedimentos (métodos). As variáveis possuem um tipo, que define os possíveis valores que a variável pode representar, como um número inteiro, número real ou string. Os métodos são rotinas que, quando executadas, realizam alguma tarefa, como alterar o conteúdo de uma variável do objeto.

Um exemplo de objeto poderia ser um automóvel. O objeto automóvel possui propriedades, como velocidade, número de portas e limite de passageiros. O objeto automóvel também possui procedimentos, como ligar, desligar, acelerar e parar. Um exemplo menos real de um objeto poderia ser um processo em um sistema operacional. Um processo tem propriedades, como identificação, prioridade, privilégios e quotas. Um processo possui procedimentos associados, como criar, eliminar, alterar a prioridade e visualizar suas caracteríticas.

Os objetos se comunicam apenas através de mensagens. Quando um objeto deseja alguma tarefa de um outro objeto, ele envia uma mensagem contendo o nome do objeto-origem, nome do objeto-destino, nome do método a ser ativado no objeto-destino e, se necessário, parâmetros que permitem especificar alguma função especial a ser executada pelo método. Este conceito se assemelha a chamada de uma rotina em uma linguagem tradicional. O conjunto de mensagens que um objeto pode responder é definido como protocolo de comunicação.

As variáveis de um objeto só podem ser alteradas por métodos definidos na própria classe. A única maneira de um objeto alterar as variáveis de um outro objeto é a através da ativação de um de seus métodos por uma mensagem. Este conceito, onde variáveis e métodos são visíveis apenas através de mensagens, é conhecido como encapsulamento. O encapsulamento funciona como uma proteção para as variáveis e métodos, além de tornar explícito qualquer tipo de comunicação com o objeto.

Geralmente, objetos são criados e eliminados em função da execução do programa. Um objeto pode ser instanciado (criado) por um certo período de tempo e depois eliminado, liberando o espaço de memória ocupado, em um processo automático conhecido como "garbage collection" (coleta de lixo). É possível, porém, criar-se objetos persistentes, que continuam existindo mesmo depois do término do programa que os criou. Um exemplo de objetos persistentes seriam os armazenados em Banco de Dados Orientados a Objetos (OODBMS).

Uma classe consiste de variáveis e métodos que representam características de um conjunto de objetos semelhantes. O conceito de classe é dos pilares da programação orientada a objetos, por permitir a reutilização efetiva de código.

A declaração de uma classe é similar ao dos tipos definidos pelo usuário nas linguagens de programação de alto nível. Nestas linguagens é possível definir um novo tipo de dado e declarar uma variável deste tipo. No caso de objetos, primeiro definimos uma classe com suas variáveis e métodos e, depois, declaramos um objeto desta nova classe. Um objeto é definido como sendo uma instância de uma determinada classe. A classe é estática, enquanto o objeto é dinâmico. No exemplo a seguir, escrito em C++, estamos definindo uma classe T_Ponto, onde as variáveis x e y representam a posição de um ponto na tela. Posteriormente declaramos um objeto p da classe T_Ponto.

class T_Ponto /* Define a classe Ponto */
{
     int x;
     int y;
public
    void altera_xy (int a, int b)
    {
         x=a;
         y=b;
     }
     int obtem_x () { return x; }
     int obtem_y () { return y; }
};

T_Ponto p; /* Declara o objeto p da classe Ponto */

No mesmo exemplo, para alterarmos o valor das variáveis x e y é necessário o envio de uma mensagem para o objeto p, especificando o método altera_xy e passando os novos valores como parâmetros. Da mesma forma, para se consultar os valores de x e y é preciso acionar os métodos obtem_x e obtem_y, respectivamente. Os métodos que permitem a comunicação do objeto com o mundo exterior são conhecidos como interfaces públicas (public).

O conceito de herança permite definir uma nova classe, com base em uma já existente. A classe criada (subclasse ou classe derivada) automaticamente herda todas as variáveis e métodos da classe já existente (superclasse). O mecanismo de herança permite ainda que a subclasse inclua ou sobreponha novas variáveis e métodos da superclasse.

O mecanismo de herança é recursivo, permitindo criar-se uma hierarquia de classes. Nos níveis mais altos da hierarquia estão características comuns a todos os objetos desta classe, enquanto nos níveis inferiores estão especializações das classes superiores. As subclasses herdam as características comuns, além de definirem suas propriedades específicas.

Existem dois tipos de mecanismos de implementação de herança: simples e múltipla. Na herança simples, a subclasse pode herdar variáveis e métodos apenas de uma classe, enquanto na herança múltipla, a subclasse pode herdar variáveis e métodos de mais de uma classe.

Uma das grandes vantagens da programação OO é a utilização de bibliotecas de classes. Estas bibliotecas lembram as bibliotecas de código (procedimentos e funções), utilizadas na programação modular. As bibliotecas de classes permitem uma capacidade muito maior de compartilhamento e reutilização de código, pois é possível criar-se subclasses para atender novas necessidades, em função das classes já existentes. Muitas bilbiotecas são oferecidas juntamente com as ferramentas de desenvolvimento para reduzir o tempo e a complexidade de projetos de software, como a Microsoft Foundation Class (MFC) e a Visual Component Library (VCL) do Delphi. Hoje existe uma crescente insdústria de componentes, isto é, empresas que dedicam a criar classes que servirão para que outros literalmente montem suas aplicações finais.

O termo polimorfismo é utilizado em biologia para definir variações em forma e função de membros de uma mesma espécie. Utilizando a mesma anologia, o mecanismo de polimorfismo permite tratar objetos semelhantes de uma maneira uniforme. Neste caso, é possível que se envie uma mesma mensagem para um conjunto de objetos e que cada objeto responda de maneira diferente em função da mensagem recebida.

O polimorfismo para ser implementado exige a utilização do conceito de herança e aplica-se apenas aos métodos da classe. O protocolo de comunicação é estabelecido na classe mais alta da hierarquia, que será herdada por todas as subclasses definidas posteriormente. Este mecanismo cria um protocolo padrão de comunicação com um conjunto de objetos, permitindo uma grande flexibilidade na agregação de objetos semelhantes, mas não idênticos.

Em programas que não utilizam orientação por objetos, sempre que uma nova funcionalidade deve ser acrescentada, a aplicação deve ser alterada e recompilada. Com o conceito de polimorfismo, é possível acrescentar novos métodos a classes já existentes sem a necessidade de recompilar a aplicação. Isto é possível através da técnica de "late binding" ou "dynamic binding", que permite que novos métodos sejam carregados e ligados (binding) à aplicação em tempo de execução.

Concluindo, baseado nos conceitos de objetos, classes, encapsulamento, herança e polimorfismoo, o paradigma da OO representa uma forma evolucionária de pensar e desenvolver software, trazendo inúmeros benefícios à criação de programas, dentre os quais o mais notável é a reutilização de código, que reduz drasticamente os tempos de desenvolvimento e manutenção de programas.

Este artigo foi escrito por Luiz Paulo Maia (lpmaia@training.com.br) e Edurado Morelli (etmorelli@ax.ibase.org.br).

Referências:

Object-Oriented Programming: An Introduction
Greg Voss, McGraw-Hill, 1991.

Object-Oriented Software
Ann L. Winblad, Samuel D. Edwards & David R. King
Addison-Wesley, 1990.