Introdução a Programação Orientada a Objetos (Parte 1)

Em: 30/12/2007 Tags: Referencie do seu blog (Trackback)

Este artigo tem por objetivo apresentar a programadores iniciantes o que é o paradigma de programação orientada a objetos (POO). Esta primeira parte apresentará os conceitos básicos desse paradigma, ilustrados com código escrito na linguagem orientada a objetos C+ou- (minha linguagem de programação fictícia que mistura as sintaxes de PHP, Python em Ruby).

Após a conclusão desta série introdutória apresentarei a POO dentro de linguagens populares como PHP5, Python e Ruby.

Antes de entender o mundo dos objetos vamos a algumas questões essenciais.

A POO é obrigatoriamente necessária?

Resposta curta: não.

Resposta longa: depende da linguagem de programação que você estiver utilizando.

Se você estiver programando em PHP, você não será forçado em nenhum momento a utilizar o suporte da linguagem a orientação a objetos (a menos que utilize bibliotecas externas baseadas em classes). Você pode escrever o clássico programa “Hello, world!” em PHP com apenas uma linha (desconsiderando as tags do PHP):

echo "Hello, world!";

Até aí nenhum objeto, certo? echo é uma construção da linguagem, e "Hello, world!" é algo (diferente de um objeto) do tipo string. O que ele realmente é não nos importa muito neste momento.

Então PHP conta 1 ponto para a minha resposta curta (não, a POO não é obrigatoriamente necessária). Mas Java conta um ponto para a resposta longa. O mesmo programa “Hello, world!” em Java não sai por menos que isso:

public class Program {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Em PHP o programa era muito mais simples, certo? O que são todas essas palavras? public, class? Bom, tudo isso em a ver com a orientação a objetos nessa linguagem. Ou seja, seu programinha mais básico em Java não pôde se esconder da POO.

O que é a POO?

A programação orientada a objetos é, antes de tudo, um paradigma de programação: é uma forma, nem mais certa e nem mais errada que as outras, de escrever software. Entre os paradigmas mais conhecidos estão:

  • Procedural
  • Funcional
  • Lógico
  • Orientado a Objetos

O paradigma de orientação a objetos é uma evolução do paradigma procedural. No C, por exemplo, uma linguagem procedural, é possível utilizar variáveis simples (para armazenar números inteiros, por exemplo), variáveis mais complexas fornecidas pela própria linguagem (como o array), e ainda variáveis complexas definidas pelo próprio usuário (você, o programador): a estrutura (struct). Uma estrutura é uma variável que serve como “cabide” para outras variáveis. Vamos imaginar a variável música como uma estrutura:

música.nome = 'Dogs'
música.autor = 'Damien Rice'
música.duração = '4.14'

Nesse caso a variável música possui 3 variáveis internas: nome, autor e duração.

Para nos aproximarmos do conceito de objetos e troca de mensagens vamos começar a evoluir a nossa estrutura música. Queremos que uma música possua letra, e que essa letra possa ser impressa a qualquer momento (isso seria, para o nosso programa, o equivalente a tocar a música). Não queremos que a nossa letra seja uma grande string, e sim que seja um conjunto de frases.

Como a nossa linguagem C+ou- suporta arrays, podemos implementar a letra da música, simplesmente, como uma nova variável dentro de música:

música.letra[0] = 'Lalala...'
música.letra[1] = 'Lelele...'

Agora, para tocar a música, podemos construir uma simples função que recebe uma música, itera sobre cada verso da letra da música e imprime cada um deles, na seqüência em que foram definidos dentro do array letra.

função tocar_música(mús):
    frases = música.letra
    para frase em frases:
        imprimir frase + "\n";
    fim
fim

Aplicando o paradigma de orientação a objetos a esse caso, podemos encarar a música em si como um objeto. Tudo o que a música sabe sobre si mesma (seu nome, seu autor, sua duração e sua letra) são seus atributos. Tudo aquilo que a música sabe fazer (imprimir sua própria letra) são seus métodos (e correspondem às mensagens que esse objeto sabe responder).

E como construímos os nossos próprios objetos? Em geral, as linguagens orientadas a objetos suportam o conceito de classes como forma de construção de moldes para objetos. Uma classe seria uma fôrma, enquanto os objetos seriam os biscoitos que conseguimos fabricar com essa fôrma. A classe define quais são os atributos e os métodos que um objeto dessa classe terá (esse conceito sofre algumas distorções de acordo com a linguagem que estamos utilizando). Vamos definir uma classe Música na nossa linguagem C+ou-:

classe Música:
fim

A definição acima é muito simples: criamos uma nova classe, e essa classe se chama Música. Objetos dessa classe não armazenam atributos e também não sabem fazer nada (é isso que a nossa definição está dizendo!).

Toda linguagem orientada a objetos deve prover uma forma de se criar novos objetos a partir de uma classe. O termo instância, neste contexto, é utilizado para denotar a criação de um novo objeto de uma classe. Diz-se que foi criada “uma nova instãncia da classe X”.

Na linguagem C+ou-, você cria uma nova instância de uma classe simplesmente ao colocar () após o nome da classe, como no exemplo abaixo:

dogs = Música()

Neste exemplo, a variável dogs foi definida como uma instância de Música. Se tentarmos definir o nome dessa música, a seguinte instrução falharia, pois nossa classe não possui ainda nenhum atributo:

dogs.nome = 'Dogs'

E aqui entra uma questão fundamental, que define como uma linguagem OO é implementada e como ela pode ser utilizada: é possível acessar os atributos de um objeto diretamente ou não? É possível definir novos atributos para um objeto dinamicamente ou não?

Encapsulamento

O encapsulamento consiste na idéia de esconder do usuário do objeto os detalhes de sua implementação. Por exemplo: podemos armazenar a letra das nossas músicas como um array ou como uma grande seqüência de caracteres (string). O usuário desse objeto, em teoria, não deveria se preocupar com isso. Ele deve querer apenas adicionar novos versos à sua música. Vamos definir nossa classe Música (e, por conseqüência, nossas novas instâncias de Música) com o atributo não-encapsulado (público) letra (note que todos os atributos de uma classe C+ou- são prefixados dentro da classe com uma arroba (@)), e vamos definir o método imprima_letra também como público.

classe Música:
    atributo público @letra = [] // o valor padrão de @letra
                                 // é um array sem elementos - []

    método público imprima_letra():
        para frase em @letra:
            imprimir frase + "\n";
        fim
    fim
fim

O seguinte código funcionará:

dogs = Música()
dogs.letra = 'Lala'

Mas note que dentro da classe Música, @letra é um array, mas como o acesso a esse atributo está público, foi permitido que essa variável fosse definida com um valor string. Agora a nossa implementação do método imprima_letra(), que espera que @letra seja um array, vai falhar.

Esse é um dos casos onde o encapsulamento se mostra útil: podemos proteger o acesso ao atributo @letra com um método público, que recebe uma string. Note como utilizaríamos a classe Música:

dogs = Música()
dogs.adicione_verso('Lalala')
dogs.adicione_verso('Blablabla')

Agora, se quisermos que o atributo @letra mude de um array para um grande string, ou se quisermos ainda implementá-lo como uma instância da classe Letra, o código que usa a classe Música continuará funcionando, pois os detalhes de implementação estão escondidos de quem quer que esteja utilizando uma instância da classe Música.

O encapsulamento é um assunto bastante abrangente. Você precisa estudá-lo a fundo para entender em que situações você deve utilizá-lo e quando é mais prático ignorá-lo.

Construtores

Toda linguagem OO fornece um meio de se inicializar uma instância de uma classe com um conjunto de valores para seus atributos internos. Essa funcionalidade é alcançada, em todas as linguagens OO que conheço, com um método da classe que possui um nome especial. Em C+ou-, esse método é o __construtor__. Esse método é “mágico”, pois é invocado sempre que queremos criar uma nova instância de uma classe. Embora sirva para construir um novo objeto, esse método especial é chamado normalmente de construtor de classe (em inglês, class constructor).

classe Música:

    atributo público @nome
    atributo público @autor
    atributo público @duração
    atributo público @letra = []

    método público __construtor__(nome, autor, duração)
        @nome = nome
        @autor = autor
        @duração = duração
    fim

    método público imprima_letra():
        para frase em @letra:
            imprimir frase + "\n";
        fim
    fim

fim

Agora podemos criar uma nova instância de Música da seguinte forma:

dogs = Música('Dogs', 'Damien Rice', 4.14)

'Dogs', 'Damien Rice' e 4.14 são encarados pela C+ou- como os parâmetros passados para o construtor da classe. Antes de retornar uma nova instância de Música, a linguagem invoca o método __construtor__ de Música, passando esses três parâmetros. Esse método é declarado público para que possa ser invocado pelos mecanismos da linguagem.

A implementação do método é bastante simples: vinculamos cada um dos valores passados como argumento aos atributos internos do objeto.

Também definimos, a partir de agora, que os atributos nome, autor e duração são públicos, para que possamos acessá-los externamente. Eles não estão, portanto, encapsulados. O seguinte código, agora, será válido:

dogs = Música('Dogs', 'Damien Rice', 4.14)
imprimir dogs.nome + "\n"
imprimir dogs.autor + "\n"
imprimir dogs.duração + "\n"

A saída do programa será:

Dogs
Damien Rice
4.14

Para saber mais sobre construtores é mais útil consultar a documentação referente a uma linguagem de programação específica. Assim você fica conhecendo qual o nome que a linguagem utiliza para o construtor, e como ele pode ser invocado. A título de curiosidade:

  • Em Java o construtor da classe é um método com o mesmo nome da classe
  • Em PHP5 o construtor da classe é o método __construct
  • Em Python o construtor da classe é o método __init__
  • Em Ruby o construtor da classe é o método initialize

Considerações a respeito de nomenclatura

Embora eu tenha definido uma classe como um molde para a criação de novos objetos, em algumas linguagens ela pode ser muito mais que isso. Ruby, por exemplo, trata a própria classe como um objeto, a qual é capaz de criar instâncias de si mesma. Para PHP e Java, por outro lado, a classe não é um objeto (embora possa responder a certas mensagens, e confundindo a cabeça de quem tenta entender a linguagem).

É importante ter em mente, portanto, que a orientação a objetos não é vista por todas as linguagens da mesma forma. Pelo contrário, cada linguagem a implementa da forma que considera mais produtiva e/ou mais eficiente. Quando se aprende uma nova linguagem OO deve-se procurar entender o que são classes e objetos na visão dela, e até onde vão suas responsabilidades e funcionalidades.

Na próxima parte…

Na próxima parte desta série veremos:

  • Modificadores de acesso
  • Herança
  • Passagens de parâmetros por cópia e por referência
  • Encadeamento de chamadas de métodos

Se ainda houver interesse da parte dos leitores, a terceira e (talvez) última parte desta série introdutória abordará a programação funcional dentro das linguagens OO, e como a junção desses dois paradigmas pode render programas mais legíveis e poderosos.

Artigos relacionados:

  • Não há artigos relacionados

8 respostas para “Introdução a Programação Orientada a Objetos (Parte 1)”

  1. Phillip Calçado disse:

    Boa introdução, mas cuidado com algumas coisas.

    • Nem todas as plataformas OO trabalham com troca de mensagens (CLOS é um exemplo) e não, a linguagem não e obrigada a ter uma forma de instanciar um objeto à partir da classe (ela nem precisa ter classes! JavaScript é um exemplo).
    • Encapsulamento e information hiding são coisas diferentes (encapsulamento em inglês é encapsulation mesmo: http://blog.fragmental.com.br/2006/03/04/fowler-e-getters/)
    • Para ser OO uma linguagem não precisa oferecer construtores ou factory methods, isso não faz parte do paradigma em si

    De uma maneira geral evite falar que ‘toda linguagem OO’faz algo porque geralmente as linguagens implementam alguns aspectos do paradigma OO e impõem outros, esses acabam virando de facto mas não estão dentro dos padrões.

    Io, JavaScript e CLOS são modelos de objetos que ajudam a trabalhar melhor os conceitos e deixar a implementação.

    []s

  2. Luciano Pacheco disse:

    Isso:

    função tocar_música(mús): frases = música.letra para frases em versos: imprimir frase + “\n”; fim fim

    Não deveria ser:

    função tocar_música(mús): frases = música.letra para verso em frases : imprimir verso + “\n”; fim fim

  3. Caio Moritz disse:

    @Philip: seus pontos são válidos mas rigorosos demais. Como um texto introdutório, abordar as coisas da maneira precisa como você aponta tornaria a compreensão do texto impossível para os não-iniciados (ao menos eu não conseguiria fazer um texto com tantos “isso nem sempre é verdade, veja bem…”). Meu objetivo não é escrever um tutorial definitivo sobre POO, apenas um texto acessível.

    Sobre “evite falar que…”, eu evitei, afinal escrevi:

    É importante ter em mente, portanto, que a orientação a objetos não é vista por todas as linguagens da mesma forma.

    Realmente, encapsulamento e ocultamento de informação são coisas distintas, já corrigi o texto.

    @Luciano: você tem razão, consertei a falha.

    Obrigado pelo feedback ;)

  4. Phillip Calcado "Shoes" disse:

    Seu ponto é válido mas após alum tempo com trenamento e coaching eu vejo que um dos piores problemas para novatos é exatamente pensar em OO em termos de uma implementação ou outra. O fato de se vincular OO com classes, por exemlo, é um problema grave que faz com que novatos não entendam que Javacript é OO. E como a grande maioria das pessoas não passa dos textos básicos para os avançados esse ponto é importante.

    Enquanto você ensina uma linguagem está ok falar sobre apenas a implementação dela (deixando claro que não é a única, nem a ‘certa’) mas quando se trata de alar sobre o paradigma ainda que não se explique todos os conceitos envolvidos é importante deixar claro que Orientação a Obejtos é um conceito que se implementa de várias formas mas se vê de uma só.

  5. Caio Moritz disse:

    Olá, Phillip

    Começo a entender agora a importância do que você diz, principalmente pois na faculdade aprendi orientação a objetos da forma “dogmática” como essa que estou passando (você tem uma classe, então você instancia a classe e vai embora). Realmente, há muito mais do que isso, as coisas não são assim em todas as linguagens. Até hoje eu não entendi bem a orientação a objetos do JavaScript, por exemplo, simplesmente por utilizar uma outra sintaxe. Claro que eu poderia ter estudado mais, mas como estou com o pensamento sempre em classes e objetos fica difícil ver a OO dentro de outra roupa, hehe.

    Vou manter o texto como está, pois ele atende o que eu queria dizer, mas vou preparar também uma parte 3, para abordar a OO dessa forma alternativa, como você mesmo apontou, presente no Common Lisp e no JavaScript (e talvez em outras linguagens interessantes, se você quiser relacionar outras seria ótimo).

    Obrigado pelas dicas!

  6. James disse:

    Explicar OO através de cachorros e biscoitos só confunde a cabeça de quem já conhece outra linguagem, escrevo em Perl, que também tem seu OO, e para entender OO efetivamente bastaria exibir dois programas para um mesmo objetivo, um em Perl sem OO e um em Java com OO. É o novato, analisando os dois, talvez acabasse entendendo a diferença.

  7. Caio Moritz Ronchi disse:

    Eu não sou professor, não sei o que é melhor para um novato. Esta foi apenas minha tentativa de compartilhar um pouco do meu conhecimento com pessoas que não tem a oportunidade de freqüentar um curso de programação e mesmo assim querem entender o que são os tais “objetos”. Se você acredita nessa sua abordagem, escreva seu artigo, mande-me o link e eu lhe referenciarei com prazer aqui no blog.

  8. Caio Costa disse:

    “Se você acredita nessa sua abordagem, escreva seu artigo, mande-me o link e eu lhe referenciarei com prazer aqui no blog.” Boa resposta, ótimo post. Justamente o básico que eu precisava para continuar pensando em escrever orientado a objeto.

    Abraço, e aguardo a próxima parte!

Escreva um comentário (utilize o formato Markdown)