.NET - Uma revisão sobre a programação orientada a objetos(POO)


Neste artigo vou revisar os conceitos chaves sobre o paradigma da programação orientada a objetos sem rodeios.

A Programação Orientada a Objetos (POO) é uma abordagem para desenvolvimento de software no qual a estrutura do software é baseada em objetos que interagem uns com os outros para realizar uma tarefa.

Obs: Você vai encontrar com freqüência a acróstico OOP - Oriented Object Programming.

Essa interação toma a forma de mensagens que são trocadas entre os objetos sendo que em resposta a uma mensagem um objeto pode executar uma ação ou método.

O mundo é um sistema orientado a objetos

Se você parar para pensar em como você realiza as suas tarefas no mundo ao seu redor você vai perceber que interage em um mundo orientado a objetos.

1- Para provar isso pense em uma tarefa que você realiza com freqüência : Ir ao Shopping.

- Se você quiser ir até ao Shopping, por exemplo, você interage com um objeto veículo (Carro, ônibus, táxi, etc. Isso não importa. Só não vale ir a pé...) ;

- Um objeto veículo consiste de outros objetos que interagem uns com os outros para realizar a tarefa de levar você até ao Shopping;

- Você coloca a chave no objeto ignição e o aciona;

- Este por sua vez, envia uma mensagem (através de um sinal elétrico) para o objeto partida, que interage com o objeto motor para ligar o veículo;

- Como um motorista você está isolado da lógica de como os objetos do sistema trabalham em conjunto (enviando mensagens) para ligar o veículo;

- Você só tem apenas que iniciar a seqüência de eventos, executando o método iniciar do objeto ignição e dessa forma você então espera por uma resposta (mensagem) de sucesso ou fracasso.

O Software e o paradigma da orientação a objetos

Da mesma forma, os usuários de programas de software são isolados a partir da lógica necessária para realizar uma tarefa.

Vejamos um exemplo comum do dia dia: Imprimir uma página.

- Quando você imprime uma página em seu processador de texto, você inicia a ação clicando em um botão Imprimir;

- Você está isolado do processamento interno que precisa ocorrer, você só espera por uma resposta dizendo-lhe se a página foi impressa ou não;

- Internamente, o objeto botão interage com um objeto impressora que interage com a impressora para realizar a tarefa de imprimir a página;

Os conceitos sobre orientação a objetos são antigos

Os Conceitos POO começaram a aparecer em meados dos anos 1960 com uma linguagem de programação chamada Simula e evoluiu nos anos 70 com o advento do Smalltalk.

Smalltalk-80, ou simplesmente Smalltalk, é uma linguagem de programação orientada a objeto fracamente tipada.
Em Smalltalk tudo é objeto: os números, as classes, os métodos, blocos de código, etc.
Não há tipos primitivos, ao contrário de outras linguagens orientadas a objeto; strings, números e caracteres são implementados como classes em Smalltalk,
por isso esta linguagem é considerada puramente orientada a objetos. Tecnicamente, todo elemento de Smalltalk é um objeto de primeira ordem.
(
http://pt.wikipedia.org/wiki/Smalltalk)

Embora os desenvolvedores de software não abraçassem de imediato esses avanços nas linguagens POO, a metodologia orientada a objetos continuou a evoluir.

Em meados dos anos 80 houve um ressurgimento do interesse nas metodologias orientadas a objetos.

Neste momento linguagens POO como C++ e Eifle tornaram-se popular junto aos programadores dos computadores pessoais (Personal Computer).

Na década de 90 a POO continuou a crescer em popularidade, principalmente com o advento do Java, que atraiu uma grande quantidade de seguidores.

Em 2002, em conjunto com o lançamento do Framework. NET, A Microsoft introduziu uma nova linguagem POO, chamada C# (pronuncia-se C-sharp) e remodelou a linguagem Visual Basic para que ela se tornasse uma linguagem com suporte total a POO.

Usando a abordagem da orientação a objetos (POO). Por quê ?

Por que a abordagem do paradigma POO tem se desenvolvido de forma a ser amplamente utilizada para resolver os problemas de negócio dos dias atuais ?

Durante os anos 70 e 80, as linguagens procedurais como C, Pascal, Fortran, etc. foram amplamente usadas para desenvolver sistemas de negócios de software.

Pascal é uma linguagem de programação estruturada, que recebeu este nome em homenagem ao matemático Blaise Pascal.
Foi criada em 1970 pelo suíço Niklaus Wirth, tendo em mente encorajar o uso de código estruturado.(
http://pt.wikipedia.org/wiki/Pascal_(linguagem_de_programa%C3%A7%C3%A3o))

Linguagens procedurais organizam o programa de forma linear e utilizam um fluxo de execução de cima para baixo. Em outras palavras, o programa é executado em uma série de passos que são executados um após o outro.

O termo Programação procedural (ou programação procedimental) é as vezes utilizado como sinônimo de Programação imperativa (Paradigma de programação que especifica os passos que um programa deve seguir para alcançar um estado desejado), mas o termo pode se referir (como neste artigo) a um paradigma de programação baseado no conceito de chamadas a procedimento.
Procedimentos, também conhecidos como rotinas, subrotinas, métodos, ou funções (que não devem ser confundidas com funções matemáticas, mas são similares àquelas usadas na programação funcional) simplesmente contém um conjunto de passos computacionais a serem executados. Um dado procedimento pode ser chamado a qualquer hora durante a execução de um programa, inclusive por outros procedimentos ou por si mesmo.
(http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_procedural)

Este tipo de programação funcionou bem para pequenos programas que consistiam de algumas centenas linhas de código, mas connforme os programas se tornaram maiores e mais complexos eles se tornaram mais difíceis de gerir e depurar.

Em uma tentativa de gerenciar o tamanho cada vez maior de programas, a programação estruturada foi introduzida para quebrar o código em segmentos gerenciáveis chamados de funções ou procedimentos.

Isso foi uma melhoria, mas como os programas passaram a ter que realizar funcionalidade de negócios mais complexas e interagirem com outros sistemas, as seguintes deficiências da metodologia de programação estrutural começaram a aflorar:

Os problemas da abordagem procedural

Além dessas deficiências, a evolução dos sistemas computacionais causou uma forte tensão sobre a abordagem adotada pelos estruturais, e os usuários passaram a exigir uma abordagem mais intuitiva e menos estruturada de forma a interagir de forma mais fácil com os programas.

Além disso os sistemas evoluíram para um modelo distribuído onde a lógica de negócio, a interface com o usuário e a camada de acesso a dados estavam fracamente acopladas e eram acessadas através da internet e intranet.

Como resultado, muitos desenvolvedores de software passaram a adotar a metodologia orientada a objetos e as linguagens de programação com suporte a POO para resolver esses problemas e com o objetivo de obter os seguintes benefícios:

Os benefícios da abordagem Orientada a objetos(POO)
As características da Programação Orientada a Objetos (OOP)

Os conceitos básicos e os termos comum a todas as linguagens orientada a objetos.

Objetos

Conforme disse anteriormente, vivemos em um mundo orientado a objetos. Você é um objeto. Você interage com outros objetos.

Na verdade, você é um objeto com dados como altura e cor do cabelo. Você também tem métodos que você executa ou são executadas em você, como comer e andar.

Então, o que são objetos ?

Em termos da POO, um objeto é uma estrutura que incorpora dados e procedimentos para trabalhar com esses dados.

Assim, um objeto é capaz de armazenar estados através de seus atributos e reagir a mensagens enviadas a ele, assim como se relacionar e enviar mensagens a outros objetos.

Por exemplo, se você estivesse interessado em tratar os dados associados com produtos em estoque, você criaria um objeto produto que é responsável pela manter e trabalhar com os dados relativos dos produtos.

Se você desejar ter a capacidade de impressão em seu aplicativo, você vai trabalhar com um objeto impressora que é responsável pelos dados e métodos utilizados para interagir com suas impressoras.

No contexto da OOP um objeto é uma instância de uma classe. Onde a classe é o tipo e o objeto é uma instância do tipo. Ex: classe Cliente -> objeto macoratti.

Abstração

Quando você interage com objetos no mundo, que são muitas vezes preocupada apenas com um subconjunto de suas propriedades. Sem esta capacidade de abstrair ou filtrar as propriedades de objetos você teria muita dificuldade para processar o excesso de informação que bombardeia você e se concentrar na tarefa em mãos.

Como resultado de abstração, quando duas pessoas diferentes interagem com o mesmo objeto, eles freqüentemente lidam com um subconjunto de atributos diferentes. Quando dirijo meu carro, por exemplo, eu preciso saber a velocidade do carro e a direção em que ele está indo.

Se o carro for automático, não preciso saber nada sobre o giro do motor, assim essa informação é filtrada. Por outro lado, esta informação seria fundamental para um motorista de um carro não automático ou de carro de corrida e assim ela não seria filtrada.

Ao construir objetos em aplicações OOP é importante incorporar esse conceito de abstração.

Se você estivesse construindo uma aplicação para remessa de produtos, você poderia construir um objeto produto com atributos como tamanho e peso. A cor do item seria uma informação irrelevante e filtrada. Por outro lado, ao construir uma aplicação de entrada de pedidos, a cor pode ser importante e seria incluído como um atributo do objeto produto.

Dessa forma abstração é a habilidade de concentrar-se nos aspectos essenciais de um contexto qualquer, ignorando características menos importantes ou não essenciais. Em modelagem orientada a objetos, uma classe é uma abstração de uma entidade existente no domínio do sistema de software. Exemplos de classes: Pedido, Produto, Cliente, etc.

Encapsulamento

Outra característica importante da OOP é o encapsulamento.

Encapsulamento é o processo no qual o acesso direto aos dados de um objeto não é permitido, em vez disso, ele está escondido.

Se você quiser ter acesso aos dados, você tem que interagir com o objeto responsável pelos dados. Em uma aplicação para inventário, se você quisesse visualizar ou atualizar informações sobre os produtos, você teria que trabalhar com o objeto produto e para ler os dados, você poderia enviar uma mensagem ao objeto Produto e o objeto Produto, então, iria ler o valor do dado e enviar de volta uma mensagem dizendo qual é o valor. O objeto produto define quais operações podem ser realizadas sobre os dados do produto.

Se você enviar uma mensagem para modificar os dados eo objeto produto determina que é um pedido válido, ele irá executar a operação para você e enviar uma mensagem de volta com o resultado.

O encapsulamento esta presente no nosso dia a dia. Pense em um departamento de recursos humanos (o departamento de pessoal - DP). Um departamento pessoal geralmente encapsula a informação sobre os empregados determinando como e quando esses dados podem ser manipulados. Qualquer solicitação ou atualização dos dados de um empregado tem que ser filtrado pelo DP sendo que ninguém pode ter acesso aos dados a não ser através do departamento pessoal.

O encapsulamento dos dados os torna mais seguros e confiáveis pois você sabe como os dados estão sendo acessados e quais operações estão sendo realizadas sobre os mesmos.

O ato de empacotar ao mesmo tempo dados e objetos é denominado encapsulamento. O objeto esconde seus dados de outros objetos e permite que os dados sejam acessados por intermédio de seus próprios métodos. Isso é chamado de ocultação de informações (information hiding).

Polimorfismo

Polimorfismo (do grego: poli= muitas morphos=formas) é a habilidade de objetos distintos responderem a mesma mensagem de a sua própria maneira.

Eu posso treinar o meu cachorro para responder ao comando latir e o meu gato a responder ao comando miar mas posso treiná-los também para responder ao comando falar. Através do polimorfismo eu sei que ao receber o comando falar o meu cachorro irá responder com um latido e o meu gato com um miado. (pelo menos esse é o comportamento considerado normal)

No contexto OOP podemos criar objetos que respondem a mesma mensagem de forma única de acordo com sua implementação. Assim, por exemplo, podemos enviar uma mensagem para um objeto Impressora para imprimir um texto na impressora e podemos enviar a mesma mensagem para a tela para imprimir o texto um formulário na tela do computador.

No contexto OOP podemos implementar esse tipo de polimorfismo através de um processo chamado sobrecarga. Fazemos isso implementando diferentes métodos de um objeto com o mesmo nome mas assinaturas diferentes. O objeto pode dessa forma chamar qual método usar dependendo do contexto da mensagem. Como exemplo podemos implementar dois métodos para procurar um produto em um estoque da seguinte forma:

Um objeto pode então usar o método getProduto() passando ou o nome ou o preço para localizar um produto.

Herança

A maioria dos objetos são classificados de acordo com hierarquias. Por exemplo, você pode classificar todos os cães como tendo certas características comuns, tais como ter quatro patas e pelos.

Suas raças podem classificá-los, posteriormente, em subgrupos com atributos comuns, tais como tamanho e comportamento.

Você também classificar objetos de acordo com sua função. Por exemplo, existem veículos comerciais e veículos de recreio, existem caminhões e automóveis de passageiros. Você classifica veículos de acordo com sua marca e modelo.

Para tornar o mundo mais coerente você precisa usar hierarquias de objetos e classificações.

Dessa forma você usa a herança em OOP para classificar os objetos em seus programas de acordo com características e funções comuns. Isso torna o trabalho com os objetos mais fácil e intuitivo e também torna a programação mais fácil, porque ela permite que você combine as características gerais para um objeto pai e herde estas características nos objetos filhos.

Por exemplo, você pode definir um objeto empregado que define todas as características gerais dos funcionários em sua empresa. Você pode, então, definir um objeto gerente que herda as características do objeto empregado, mas também adiciona características exclusivas para gerentes de sua empresa.

É comum haver similaridades entre diferentes classes. Freqüentemente, duas ou mais classes irão compartilhar os mesmos atributos e/ou métodos. Como nenhum de nós deseja reescrever várias vezes o mesmo código, seria interessante se algum mecanismo pudesse tirar proveito dessas similaridades. A herança é esse mecanismo. Por intermédio da herança, é possível modelar relacionamentos do tipo "é" ou "é semelhante", o que nos permite reutilizar rotinas e dados já existentes.

Uma subclasse herda as propriedades de sua classe-pai também chamada superclasse. Uma subclasse pode herdar a estrutura de dados e os métodos, ou alguns dos métodos, de sua superclasse. A subclasse também tem métodos e às vezes, tipos de dados próprios.

Subclasse – uma classe que é um subtipo de uma ou mais classes (denominadas superclasses). Como tal, ela herda todas as características de suas superclasses. Em outras palavras, todas as características de uma classe são reusáveis por suas subclasses. Se a classe B herda de A, então dizemos que B é uma subclasse de A.

Superclasse – Uma classe que é um supertipo de uma ou mais classes (também chamadas de subclasses). Como tal, ela é uma classe a partir da qual todas as suas características são herdadas por suas subclasses. Em outras palavras, todas as características de uma superclasse são reusáveis por aquelas classes que são seus subtipos. Se a classe B herda de A, então dizemos que A é uma superclasse de B.

Agregação

A agregação ocorre quando um objeto consiste de uma composição de outros objetos que trabalham juntos. Por exemplo, o objeto carro é um composto de objetos roda, objeto motor, objeto da farol, objeto direção, etc. Juntos todos esses objetos compõem o objeto carro.

Na verdade, o objeto motor é um composto de muitos outros objetos. Assim há muitos exemplos de agregação no mundo que nos rodeia. A capacidade de usar agregação em POO é um poderoso recurso que permite modelar e implementar com precisão processos de negócios em seus programas.

A POO utiliza a agregação como o mecanismo de reaproveitamento de classes para aumentar a produtividade e a qualidade no desenvolvimento de software.

Dessa forma ao reutilizar uma classe você pode usar uma ou várias classes para compor outra classe e como as classes que estão sendo aproveitadas já existem você não precisa reescrever o seu código aumentando assim a produtividade.

Além destes conceitos básicos existem também os princípios SOLID.

Os princípios SOLID para programação e design orientados a objeto são de autoria de Robert C. Martin (mais conhecido como Uncle Bob) e datam do início de 2000.

A palavra SOLID é um acróstico onde cada letra significa a sigla de um princípio: SRP, OCP, LSP, ISP e DIP

Obs: Os acrósticos são formas textuais onde a primeira letra de cada frase ou verso formam uma palavra ou frase

Na tabela abaixo vemos cada sigla, o seu significado e um resumo do princípio a que se refere no original e em uma tradução livre.

SRP The Single Responsibility Principle
Principio da Responsabilidade Única
Uma classe deve ter um, e somente um, motivo para mudar.
A class should have one, and only one, reason to change.
OCP The Open Closed Principle
Princípio Aberto-Fechado
Você deve ser capaz de estender um comportamento de uma classe, sem modificá-lo.
You should be able to extend a classes behavior, without modifying it.
LSP The Liskov Substitution Principle
Princípio da Substituição de Liskov
As classes derivadas devem ser substituíveis por suas classes base.
Derived classes must be substitutable for their base classes.
ISP The Interface Segregation Principle
Princípio da Segregação da Interface
Muitas interfaces específicas são melhores do que uma interface geral
Make fine grained interfaces that are client specific.
DIP The Dependency Inversion Principle
Princípio da inversão da dependência
Dependa de uma abstração e não de uma implementação.
Depend on abstractions, not on concretions.

Os princípios SOLID devem ser aplicados no desenvolvimento de software de forma que o software produzido tenha as seguintes características:

"Meus filhinhos , estas coisas vos escrevo, para que não pequeis; e se alguém pecar, temos um advogado para com o Pai, Jesus Cristo, o justo." I João 2:1

Referências:


José Carlos Macoratti