Pilares da Programação Orientada a Objetos (POO) — Uma abordagem teórica.
Orientação a Objetos é mais um paradigma da programação, sendo uma excelente ferramenta para resolver problemas complexos. Algumas linguagens como Java, C# e Python são fortemente orientadas a objetos e ajudam a compreender alguns conceitos, porém meu objetivo com esse artigo é definir as bases da POO sem utilizar exemplos reais de programação e abusando de associações e abstrações. Portanto, não iremos criar nenhuma conta bancária aqui, embora esse seja um excelente exemplo.
“O paradigma da POO oferece aos programadores uma maneira eficiente de combinar código e dados em unidades coesas que muitas vezes são altamente reutilizáveis”¹. Considero que a definição de Irv Kalb define em uma frase dois pilares da POO: encapsulamento e herança. Os demais pilares são abstração e polimorfismo.
🧬Abstração
Abstrato é aquilo que não é concreto nem real; que não tem existência como objeto, como coisa, como realidade palpável; irreal². Na programação, abstrair é selecionar todas as características de algo real que acreditamos que defina um objeto, uma coisa. Tome como a imagem da Fig.1, você rapidamente já identificará a cor e até a espécie do animal.
A legenda “uma galinha marrom” já é uma abstração. Ela define características de algo concreto, muitas vezes com características também abstratas (não existe “um marrom”, existe “algo marrom”). A Tab. 1 define essas e outras características das galinhas:
Em resumo quando abstraímos, definimos um “projeto”, um “modelo”, ou um “molde” que nos permita criar algo concreto, objetos. No caso da galinha e outros seres vivos (e virus) os cientistas já conseguem sequenciar o DNA. Em nosso exemplo a sequencia de DNA da galinha contém todas as informações que precisamos para criar uma galinha, conforme ilustrado pela Fig. 2. Para simplificar, nas próximas seções chamaremos “sequencia de DNA” apenas como DNA, embora sejam coisas diferentes.
Note novamente que o DNA é uma abstração, contém de maneira não física tudo aquilo que precisamos para criar uma galinha. Se você já estuda programação, o DNA é a classe (parte abstrata) que cria o objeto galinha (parte concreta).
A partir dessa abstração podemos gerar quantos objetos necessitarmos, conforme ilustrado pela Fig. 3. Podemos pensar no DNA como a abstração da POO, a partir de uma única abstração podemos criar quantos objetos forem necessários.
👪 Herança
Herança é o pilar mais simples da POO, mas é um dos mais importantes mecanismos para maximizar a reutilização de código. A Herança permite utilizarmos uma abstração já existente, e criar um nova abstração utilizando a antiga como base. É importante salientar aqui que estamos criando uma nova abstração a partir da anterior, um novo “DNA”. No exemplo da Fig. 4 o DNA da galinha é utilizado para gerar um DNA de um corvo e, a partir dele, geramos novos objetos (corvos). Nesse processo herdamos as características que quisermos (corvos e galinhas possuem asas, bicos, e podem até ter comportamentos semelhantes), podendo alterar valores (como cor e tamanho) assim como adicionar comportamentos (capacidade de imitar a voz humana dos corvos, por exemplo).
💊 Encapsulamento
No exemplo dado na Tabela 1 já estamos utilizando encapsulamento. Encapsular é manter tudo que define as características físicas e comportamentais dentro de uma única cápsula, uma única abstração. O DNA da galinha tem todo o comportamento e características da galinha, assim como o DNA do corvo possui todo o comportamento e características do corvo. O corvo sabe voar pois essa habilidade nasce com ele, ele não recebe uma atualização de DNA com novos comportamentos. Encapsular também nos permite esconder detalhes de implementação deixando visível e acessível apenas o que for estritamente necessário para executar o comportamento.
🐸 Polimorfismo
Em resumo polimorfismo quer dizer “muitas formas”. Considero Polimorfismo o conceito mais complexo e, quando aliado a herança, o mais poderoso deles. Em Object-Oriented Python — Master OPP by building games and GUIs¹ Irv Kalb fornece um excelente exemplo de polimorfismo. Em uma tradução livre:
Como um exemplo real, imagine-se em uma sala com um interruptor na parede controlando diferentes tipos de lâmpadas. Algumas dessas lâmpadas são incandescentes, outras fluorescentes, outras novíssimas lâmpadas de LED. Quando você aciona o interruptor envia uma ordem de “acender” a todas as lâmpadas. O funcionamento interno das lâmpadas incandescentes, fluorescentes e LED para emitir luz é completamente diferente, mas todas irão se acender. — Irv Kalb¹
Esse exemplo apresenta umas das habilidades do polimorfismo, diferentes classes podem ter comportamentos diferentes como resposta ao um mesmo comando. Na Fig. 5 vemos que Galinhas e Corvos possuem a capacidade de voar, mas quando o fazem, voam de maneira completamente diferente.
Outro poder do polimorfismo é enunciado por Erich Gamma, Richard Helm, Ralph Johnson e John M. Vlissides³ também em tradução livre: “A habilidade de substituir objetos de uma abstração para outra em tempo de execução”. Apesar de mais técnica, a afirmação de Erich Gamma et al. evidencia a capacidade de alguns objetos (galinhas) passarem-se como outros (corvos) em determinadas situações. Imagine que você nunca tenha visto nem um corvo nem uma galinha; se lhe dissessem: “Corvos são aves pretas que comem pipoca!” e você visse uma galinha preta comendo pipoca, você provavelmente diria: “Isso é um corvo!”.
Perceba na Fig. 6 que dadas as restrições (ave, preta, e comendo pipoca) você não está errado, nesse caso a galinha comportou-se como um corvo. Com o polimorfismo, podemos generalizar as ordens e reutiliza-las para diferentes aplicações.
O polimorfismo aliado a herança contribui para darmos ordens mais genéricas, favorecendo a reutilização de código. Observando a Fig. 7 podemos definir que tanto as Galinhas quanto os Corvos podem ser encaixados como uma abstração comum chamada “Aves” ou seja, estabelecem também uma relação de herança. Logo, se quisermos construir um paraíso de aves, podemos dar ordem “Peguem todas as aves!” ao invés de “Peguem todas as galinhas, corvos, etc!”.
Considerações finais
A POO é uma poderosa ferramenta para solucionar problemas complexos. Por ser um paradigma da programação, várias linguagens a implementam de forma diferente, e é preciso estudar cada uma para sua melhor utilização. Diversos patterns³ também podem ser utilizados para fazer o melhor uso possível da herança e polimorfismo variando de acordo com o problema a ser resolvido. Retornar as bases e fazer associações com outras áreas do conhecimentos é uma boa maneira de compreender um conceito complexo. Espero que o tenha ajudado no entendimento desses conceitos.
— -
¹Object-Oriented Python: Master OOP by Building Games and GUIs (English Edition) — Irv Kalb, em tradução livre.
²Dicionário on line de português.
³Design Patterns: Elements of Reusable Object-Oriented Software — Erich Gamma, Richard Helm, Ralph Johnson e John M. Vlissides
— -
Você utiliza a POO e tem contribuições com esse artigo? Não deixe de entrar em contato comigo para que possamos melhora-lo.