Orientação a Objetos
Prof. Ricardo Nogueira
1
Capítulo 1 – Classes
Pois bem, aqui começamos com o detalhamento dos conceitos elementares da programação orientada a objetos. Eu
arriscaria dizer que uma eventual dificuldade de entendimento deste assunto não deriva da incapacidade de se abstrair
uma idéia ou de se discutir um conceito, mas sim da dificuldade de migrar um conjunto de proposições do campo da
imaginação e sintetizá-los em algo que, verdade seja dita, não se materializará necessariamente naquele conceito tal
como foi proposto.
Se pudermos dar uma primeira definição do que consiste o paradigma da orientação a objetos, afirmaremos que “é um
jeito de programar cuja formatação do código gerado inspira-se no conceito que define o que são e como funcionam os
objetos”. Isto posto, vamos imaginar um cientista que decida criar um robô por simples passa-tempo. Depois de gastar
algumas semanas estudando o assunto, ele desenvolve um documento de requisitos, onde se lê o seguinte:
Especificações técnicas:
- Altura: 150 cm;
- Largura: 50 cm;
- Material: alumínio;
- Sensores: 01, de presença;
- Alto-falante;
- Botão liga-desliga fazendo as vezes de um nariz.
Capacidades:
- Falar;
- Mover braços e pernas;
- Detectar objetos que se movimentem ao redor;
A partir desse documento, nosso cientista desenvolve um primeiro projeto de robô, como indicado na figura 1.1.
Especificações:
- Altura: 150 cm;
- Largura: 50 cm;
- Material: alumínio;
- Sensores: 01, de presença;
- Alto-falante;
- Botão liga-desliga no nariz
Projeto de Robô
Quis o acaso que um programador, também por pura diversão, tenha decidido criar um robô, só que virtual e usando
uma linguagem de programação orientada a objetos para atingir este objetivo. Depois de também ter gasto algum tempo
estudando o assunto, nosso programador criou um documento onde constam seus requisitos de projeto. Nesse
documento lemos o seguinte:
Características:
- Código de identificação;
2
- Modelo;
- Data de criação.
Capacidades:
- Identificar-se perante um usuário;
- Fazer cálculos matemáticos;
Uma vez feita a especificação, o programador pôs mãos à obra, criou um arquivo texto onde digitou o programa usando
a linguagem orientada a objetos e salvou esse arquivo-texto em uma pasta qualquer do computador. Muito bem! Assim
como o nosso cientista criou um projeto a partir das especificações técnicas e das características desejadas para o seu
robô contidas no documento de requisitos, o nosso programador criou um arquivo-texto onde representou, em
linguagem OO, as características e capacidades do seu robô virtual com base em seu documento de requisitos de
projeto. Aquilo que o cientista chama de “projeto” – uma folha de papel onde detalha os requisitos do robô – o
programador chama de “classe” ao arquivo-texto com a lógica de programação que traduz os requisitos de projeto do
robô virtual.
Nome da classe
Atributos
Métodos
Construtores
Métodos de acesso
Métodos comuns
Método executável
Vejamos, de um modo bastante simples e resumido, o que é e para que serve cada um desses elementos:
· Nome da classe: toda classe tem que ter um nome, a critério do programador. A linguagem Java diferencia
maiúsculas de minúsculas, ou seja, dar a uma classe o nome de Robo não é a mesma coisa que chamá-la de
robo; para o Java, serão duas classes distintas. Toda classe possui a extensão .class para indicar que estamos
lidando, sem sombra de dúvida, com uma classe; assim, poderíamos ter uma classe chamada Robo.class.
· Atributos: representam as características intrínsecas de uma classe. Podemos afirmar também que o estado, a
condição em que se encontrará um objeto criado a partir dessa classe será determinada pelos seus atributos.
Veremos o que isso significa mais à frente.
· Métodos: representam as capacidades de uma classe, ou seja, tudo aquilo que ela é capaz de fazer, de executar.
Os métodos nos remetem à idéia de ação, de colocar alguma coisa em prática.
A estrutura de uma classe pode começar muito simples, contendo apenas um nome e nada mais (ainda que uma classe
assim não tenha utilidade alguma) até alcançar um nível bastante complexo, contendo inúmeros atributos e métodos.
3
características que ele definiu para o robô virtual foram: código de identificação, modelo e data de criação. Bem menos
estimulante.
Vamos supor que essa tela seja a materialização, o objeto gerado a partir de uma classe chamada Cliente. Podemos
observar que a tela possui uma tarja superior onde se lê: Cadastro de Clientes, alguns textos seguidos de suas
respectivas caixas de texto e alguns botões. O responsável, na classe Cliente, por determinar como essa tela de cadastro
deverá ser “construída” e exibida na tela do computador é responsabilidade do método construtor dessa classe. E para
uma classe do tipo Robô apresentada anteriormente, o que o método construtor faz? Uma das coisas que ele é capaz de
fazer é associar valores aos atributos dessa classe.
Suponha que exista uma classe chamada ContaCorrente com um atributo saldo que indica a quantia em dinheiro
disponível nessa conta. Se fosse possível acessar o atributo saldo sem os métodos de acesso, é bem possível que o
proprietário dessa conta-corrente decidisse alterar o valor de seu saldo negativo para outro muito positivo, na casa dos
milhões de reais... nada mal para ele, mas isso não acontece na vida real. Porque?
Porque a classe ContaCorrente possui métodos de acesso que restringem a forma de alteração do atributo saldo.
Supondo que os métodos de acesso tenham os seguintes nomes: sacar e depositar, não há nenhuma outra forma de
alterar o atributo saldo a não ser sacando dinheiro através do método de acesso sacar (e diminuindo deste modo seu
valor) ou depositando dinheiro através do método depositar (e aumentando o valor do saldo). Isso garante que o valor
do saldo dessa conta-corrente reflita apenas o resultado do total de depósitos menos o total de saques; esta é a idéia por
trás do encapsulamento. A figura 1.4 mostra o esquema de acesso de um atributo através dos métodos de acesso na
classe ContaCorrente.
4
saldo
sacar
depositar
Métodos com retorno e com parâmetros: o nosso programador definiu, em seu projeto de requisitos, que o robô
virtual deveria ser capaz de executar cálculos matemáticos, por exemplo, uma soma entre dois números. Um método
que receba dois números quaisquer e devolva o resultado da soma entre eles poderia ser utilizado para atender esse
requisito.
Métodos sem retorno e com parâmetros: um método desta categoria poderia ser utilizado para gerar um novo código
de identificação do robô virtual ao se fornecer um número aleatório qualquer para a geração do novo código. Entretanto,
o método não fornece o código gerado a partir desse número aleatório.
Métodos com retorno e sem parâmetros: em nossa classe Robô, um método desta categoria poderia ser utilizado, por
exemplo, para alterar o modelo do robô e devolver o novo modelo como retorno.
Métodos sem retorno e sem parâmetros: poderíamos utilizar um método desta categoria para definir uma data de
criação única para o robô virtual. Essa data seria padrão, definida no código e não seria devolvida como retorno.
Um aplicativo OO pode conter dezenas ou até centenas de classes para funcionar de acordo com os requisitos do projeto
que lhes deu origem, mas todo aplicativo deve conter uma, e somente uma, classe com um método executável que fará
as vezes do botão liga-desliga. Para sermos mais precisos, não é exatamente o método executável quem de fato executa
um programa OO; na verdade, ele indica ao compilador dessa linguagem qual é o ponto de partida para iniciar o
processamento do programa. Mas para fins de analogia, o exemplo do botão liga-desliga é suficiente.
O método executável possui sempre um mesmo e único nome em qualquer aplicativo e esse é outro motivo pelo qual
um aplicativo OO só pode ter um único método executável. Se tivermos dois métodos executáveis para um mesmo
aplicativo, o compilador não saberá qual dos dois utilizar para o início do processamento do programa e nada
acontecerá, ou pior, o compilador indicará a existência de mais de um método executável como erro.
5
Capítulo 2 – Objetos
Podemos iniciar este capítulo definindo um objeto como qualquer coisa perceptível pelos sentidos, uma coisa material.
Ou ainda, qualquer coisa inteligível ou perceptível pela mente, que sirva como um foco de atenção ou ação. Sendo
assim, vamos imaginar que alguém chegue até você e te proponha, com base na definição acima, que objeto pode ser
diversas coisas do mundo real: uma cadeira, um carro, um robô e por aí vai. Depois, que essa mesma pessoa te peça
para migrar esse conceito para uma linguagem de programação orientada a objetos. Como interpretar isso?
Vejamos: nosso cientista, uma vez satisfeito com as especificações técnicas e capacidades propostas por ele mesmo para
este primeiro projeto, põe mãos à obra e constrói seu primeiro robô, como indicado na figura 2.1. Se o projeto foi bem
planejado e elaborado, o resultado será um robô que atende plenamente os requisitos previstos e o cientista poderá,
inclusive, produzir muitos outros robôs com base nesse projeto, caso queira.
De forma semelhante, uma vez feita a especificação, o programador pôs mãos à obra, criou um arquivo texto onde
digitou o programa usando a sintaxe da linguagem OO adotada, salvou esse arquivo-texto em uma pasta qualquer do
computador, efetuou diversos testes para validar a lógica de programação adotada e, uma vez finalizados, executou o
programa do robô virtual, para poder vê-lo em funcionamento.
E quando o cientista transforma as especificações técnicas e as características desejadas para o seu robô em peças,
juntas, circuitos eletrônicos e parafusos, formando uma coisa inteligível ou perceptível à mente ao qual damos o nome
de robô, o programador – ao executar o arquivo-texto com o código que contém as características e capacidades do seu
robô virtual – gera um programa no computador com o qual um usuário será capaz de interagir e fazer contas. A esse
programa Java sendo executado no computador capaz de interagir com um usuário damos o nome de “objeto”.
Cód. Identificação
Fazer
Modelo cálculos
matemáticos
Construtor Data criação
Identificar-se
perante um usuário Objeto Robô
Memória RAM
6
A criação desse espaço na memória reservado para armazenar tudo aquilo que representa o robô virtual é
responsabilidade do construtor. Ao se criar um objeto, na verdade faz-se uma chamada ao construtor, que se
responsabiliza por verificar toda a estrutura do código do robô virtual bem como solicitar ao sistema operacional a
reserva de um espaço na memória RAM para armazenar adequadamente essa estrutura.
Cód. Identificação
Fazer
Modelo cálculos
matemáticos
Data criação
Identificar-se
perante um usuário Objeto Robô
Variável
R1
Memória RAM
Figura 2.3 – Referência a um objeto robô por meio de uma variável R1 do tipo robô
A variável, portanto, guarda um número que identifica a posição da memória RAM onde se encontra nosso objeto robô.
Capítulo 3 – Polimorfismo
Genericamente, polimorfismo significa: várias formas. Numa linguagem de programação orientada a objetos, isso
significa que pode haver várias formas de se fazer uma "certa coisa". Aí vem o primeiro aspecto importante: que "certa
coisa" é essa? A resposta é que estamos falando de chamadas de métodos. Portanto, em uma linguagem orientada a
objetos, o polimorfismo se manifesta em chamadas de métodos. Agora, podemos ser mais específicos sobre a definição
de polimorfismo: Polimorfismo significa que uma chamada de método pode ser executada de várias formas (ou
polimorficamente). Quem decide "a forma" é o objeto que recebe a chamada. Essa última frase é muito importante, pois
ela encerra a essência do polimorfismo. Leia a frase novamente.
Ela significa o seguinte: Se ocorre a chamada a um método de um objeto "b", então o objeto "b" decide a forma de
estruturação do método. Mais especificamente ainda, é o tipo do objeto "b" que importa. Para exemplificar melhor,
digamos que exista uma classe veículo que possua o método locomove. Então a chamada b.locomove vai ser um
deslocamento por uma estrada se o objeto "b" for um automóvel e será um deslocamento por trilhos se o objeto "b" for
um trem. O que importa, portanto, é o tipo do objeto receptor "b". A figura 3.1 ilustra este conceito.
- Locomove - Locomove
Classe Veículo
- Locomove
7
Não é qualquer objeto que pode se locomover, certo? Se eu tiver um objeto "b" representando um edifício e fizer
b.locomove, não pode sair coisa boa, porque um edifício não se locomove. Temos, portanto, que indicar de alguma
forma o tipo de objeto que pode ser usado neste lugar.
Observe que, se tivermos um programa com objetos das classes Automóvel, Trem e Avião, teremos 3 estruturações
diferentes do método locomove. A chamada b.locomove está chamando um desses três métodos, dependendo da classe
do objeto "b". Achar o método correto a ser chamado por um objeto específico chama-se dynamic binding, ou
amarração dinâmica. Isto é, temos que amarrar a chamada b.locomove a uma das codificações de locomove
dinamicamente, em tempo de execução.
Capítulo 4 – Herança
Herança é um mecanismo que permite que características comuns a diversas classes sejam consolidadas em uma classe
base, ou superclasse. A partir de uma classe base, outras classes podem ser especificadas. Cada classe derivada ou
subclasse apresenta as características (atributos e métodos) da classe base e acrescenta a elas o que for definido de
particularidade para ela. A figura 4.1 mostra um exemplo de herança.
Classe mamífero
Herança é um mecanismo que, se for bem empregado, permite altos graus de reutilização de código. A idéia é fornecer
um mecanismo simples (mas muito poderoso) para que se definam novas classes a partir de uma já existente.